
// TODOS FOR EXISTING CODE:
// Allow XQuery comments in any appropriate places
// Abstract declaration code?
// Make modular (e.g., branch off XQuery 1.1, though on same class)


(function () {

// "Constants"
var WS = '[ \t\n\\r]';


// XRegExp 1.5.0
// (c) 2007-2010 Steven Levithan
// MIT License
// <http://xregexp.com>
// Provides an augmented, extensible, cross-browser implementation of regular expressions,
// including support for additional syntax, flags, and methods

var XRegExp;

if (XRegExp) {
    // Avoid running twice, since that would break references to native globals
    throw Error("can't load XRegExp twice in the same frame");
}

// Run within an anonymous function to protect variables and avoid new globals
(function () {

    //---------------------------------
    //  Constructor
    //---------------------------------

    // Accepts a pattern and flags; returns a new, extended `RegExp` object. Differs from a native
    // regular expression in that additional syntax and flags are supported and cross-browser
    // syntax inconsistencies are ameliorated. `XRegExp(/regex/)` clones an existing regex and
    // converts to type XRegExp
    XRegExp = function (pattern, flags) {
        var output = [],
            currScope = XRegExp.OUTSIDE_CLASS,
            pos = 0,
            context, tokenResult, match, chr, regex;

        if (XRegExp.isRegExp(pattern)) {
            if (flags !== undefined)
                throw TypeError("can't supply flags when constructing one RegExp from another");
            return clone(pattern);
        }
        // Tokens become part of the regex construction process, so protect against infinite
        // recursion when an XRegExp is constructed within a token handler or trigger
        if (isInsideConstructor)
            throw Error("can't call the XRegExp constructor within token definition functions");

        flags = flags || "";
        context = { // `this` object for custom tokens
            hasNamedCapture: false,
            captureNames: [],
            hasFlag: function (flag) {return flags.indexOf(flag) > -1;},
            setFlag: function (flag) {flags += flag;}
        };

        while (pos < pattern.length) {
            // Check for custom tokens at the current position
            tokenResult = runTokens(pattern, pos, currScope, context);

            if (tokenResult) {
                output.push(tokenResult.output);
                pos += (tokenResult.match[0].length || 1);
            } else {
                // Check for native multicharacter metasequences (excluding character classes) at
                // the current position
                if ((match = real.exec.call(nativeTokens[currScope], pattern.slice(pos)))) {
                    output.push(match[0]);
                    pos += match[0].length;
                } else {
                    chr = pattern.charAt(pos);
                    if (chr === "[")
                        currScope = XRegExp.INSIDE_CLASS;
                    else if (chr === "]")
                        currScope = XRegExp.OUTSIDE_CLASS;
                    // Advance position one character
                    output.push(chr);
                    pos++;
                }
            }
        }

        regex = RegExp(output.join(""), real.replace.call(flags, flagClip, ""));
        regex._xregexp = {
            source: pattern,
            captureNames: context.hasNamedCapture ? context.captureNames : null
        };
        return regex;
    };


    //---------------------------------
    //  Public properties
    //---------------------------------

    XRegExp.version = "1.5.0";

    // Token scope bitflags
    XRegExp.INSIDE_CLASS = 1;
    XRegExp.OUTSIDE_CLASS = 2;


    //---------------------------------
    //  Private variables
    //---------------------------------

    var replacementToken = /\$(?:(\d\d?|[$&`'])|{([$\w]+)})/g,
        flagClip = /[^gimy]+|([\s\S])(?=[\s\S]*\1)/g, // Nonnative and duplicate flags
        quantifier = /^(?:[?*+]|{\d+(?:,\d*)?})\??/,
        isInsideConstructor = false,
        tokens = [],
        // Copy native globals for reference ("native" is an ES3 reserved keyword)
        real = {
            exec: RegExp.prototype.exec,
            test: RegExp.prototype.test,
            match: String.prototype.match,
            replace: String.prototype.replace,
            split: String.prototype.split
        },
        compliantExecNpcg = real.exec.call(/()??/, "")[1] === undefined, // check `exec` handling of nonparticipating capturing groups
        compliantLastIndexIncrement = function () {
            var x = /^/g;
            real.test.call(x, "");
            return !x.lastIndex;
        }(),
        compliantLastIndexReset = function () {
            var x = /x/g;
            real.replace.call("x", x, "");
            return !x.lastIndex;
        }(),
        hasNativeY = RegExp.prototype.sticky !== undefined,
        nativeTokens = {};

    // `nativeTokens` match native multicharacter metasequences only (including deprecated octals,
    // excluding character classes)
    nativeTokens[XRegExp.INSIDE_CLASS] = /^(?:\\(?:[0-3][0-7]{0,2}|[4-7][0-7]?|x[\dA-Fa-f]{2}|u[\dA-Fa-f]{4}|c[A-Za-z]|[\s\S]))/;
    nativeTokens[XRegExp.OUTSIDE_CLASS] = /^(?:\\(?:0(?:[0-3][0-7]{0,2}|[4-7][0-7]?)?|[1-9]\d*|x[\dA-Fa-f]{2}|u[\dA-Fa-f]{4}|c[A-Za-z]|[\s\S])|\(\?[:=!]|[?*+]\?|{\d+(?:,\d*)?}\??)/;


    //---------------------------------
    //  Public methods
    //---------------------------------

    // Lets you extend or change XRegExp syntax and create custom flags. This is used internally by
    // the XRegExp library and can be used to create XRegExp plugins. This function is intended for
    // users with advanced knowledge of JavaScript's regular expression syntax and behavior. It can
    // be disabled by `XRegExp.freezeTokens`
    XRegExp.addToken = function (regex, handler, scope, trigger) {
        tokens.push({
            pattern: clone(regex, "g" + (hasNativeY ? "y" : "")),
            handler: handler,
            scope: scope || XRegExp.OUTSIDE_CLASS,
            trigger: trigger || null
        });
    };

    // Accepts a pattern and flags; returns an extended `RegExp` object. If the pattern and flag
    // combination has previously been cached, the cached copy is returned; otherwise the newly
    // created regex is cached
    XRegExp.cache = function (pattern, flags) {
        var key = pattern + "/" + (flags || "");
        return XRegExp.cache[key] || (XRegExp.cache[key] = XRegExp(pattern, flags));
    };

    // Accepts a `RegExp` instance; returns a copy with the `/g` flag set. The copy has a fresh
    // `lastIndex` (set to zero). If you want to copy a regex without forcing the `global`
    // property, use `XRegExp(regex)`. Do not use `RegExp(regex)` because it will not preserve
    // special properties required for named capture
    XRegExp.copyAsGlobal = function (regex) {
        return clone(regex, "g");
    };

    // Accepts a string; returns the string with regex metacharacters escaped. The returned string
    // can safely be used at any point within a regex to match the provided literal string. Escaped
    // characters are [ ] { } ( ) * + ? - . , \ ^ $ | # and whitespace
    XRegExp.escape = function (str) {
        return str.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
    };

    // Accepts a string to search, regex to search with, position to start the search within the
    // string (default: 0), and an optional Boolean indicating whether matches must start at-or-
    // after the position or at the specified position only. This function ignores the `lastIndex`
    // property of the provided regex
    XRegExp.execAt = function (str, regex, pos, anchored) {
        regex = clone(regex, "g" + ((anchored && hasNativeY) ? "y" : ""));
        regex.lastIndex = pos = pos || 0;
        var match = regex.exec(str);
        if (anchored)
            return (match && match.index === pos) ? match : null;
        else
            return match;
    };

    // Breaks the unrestorable link to XRegExp's private list of tokens, thereby preventing
    // syntax and flag changes. Should be run after XRegExp and any plugins are loaded
    XRegExp.freezeTokens = function () {
        XRegExp.addToken = function () {
            throw Error("can't run addToken after freezeTokens");
        };
    };

    // Accepts any value; returns a Boolean indicating whether the argument is a `RegExp` object.
    // Note that this is also `true` for regex literals and regexes created by the `XRegExp`
    // constructor. This works correctly for variables created in another frame, when `instanceof`
    // and `constructor` checks would fail to work as intended
    XRegExp.isRegExp = function (o) {
        return Object.prototype.toString.call(o) === "[object RegExp]";
    };

    // Executes `callback` once per match within `str`. Provides a simpler and cleaner way to
    // iterate over regex matches compared to the traditional approaches of subverting
    // `String.prototype.replace` or repeatedly calling `exec` within a `while` loop
    XRegExp.iterate = function (str, origRegex, callback, context) {
        var regex = clone(origRegex, "g"),
            i = -1, match;
        while ((match = regex.exec(str))) {
            callback.call(context, match, ++i, str, regex);
            if (regex.lastIndex === match.index)
                regex.lastIndex++;
        }
        if (origRegex.global)
            origRegex.lastIndex = 0;
    };

    // Accepts a string and an array of regexes; returns the result of using each successive regex
    // to search within the matches of the previous regex. The array of regexes can also contain
    // objects with `regex` and `backref` properties, in which case the named or numbered back-
    // references specified are passed forward to the next regex or returned. E.g.:
    // var xregexpImgFileNames = XRegExp.matchChain(html, [
    //     {regex: /<img\b([^>]+)>/i, backref: 1}, // <img> tag attributes
    //     {regex: XRegExp('(?ix) \\s src=" (?<src> [^"]+ )'), backref: "src"}, // src attribute values
    //     {regex: XRegExp("^http://xregexp\\.com(/[^#?]+)", "i"), backref: 1}, // xregexp.com paths
    //     /[^\/]+$/ // filenames (strip directory paths)
    // ]);
    XRegExp.matchChain = function (str, chain) {
        return function recurseChain (values, level) {
            var item = chain[level].regex ? chain[level] : {regex: chain[level]},
                regex = clone(item.regex, "g"),
                matches = [], i;
            for (i = 0; i < values.length; i++) {
                XRegExp.iterate(values[i], regex, function (match) {
                    matches.push(item.backref ? (match[item.backref] || "") : match[0]);
                });
            }
            return ((level === chain.length - 1) || !matches.length) ?
                matches : recurseChain(matches, level + 1);
        }([str], 0);
    };


    //---------------------------------
    //  New RegExp prototype methods
    //---------------------------------

    // Accepts a context object and arguments array; returns the result of calling `exec` with the
    // first value in the arguments array. the context is ignored but is accepted for congruity
    // with `Function.prototype.apply`
    RegExp.prototype.apply = function (context, args) {
        return this.exec(args[0]);
    };

    // Accepts a context object and string; returns the result of calling `exec` with the provided
    // string. the context is ignored but is accepted for congruity with `Function.prototype.call`
    RegExp.prototype.call = function (context, str) {
        return this.exec(str);
    };


    //---------------------------------
    //  Overriden native methods
    //---------------------------------

    // Adds named capture support (with backreferences returned as `result.name`), and fixes two
    // cross-browser issues per ES3:
    // - Captured values for nonparticipating capturing groups should be returned as `undefined`,
    //   rather than the empty string.
    // - `lastIndex` should not be incremented after zero-length matches.
    RegExp.prototype.exec = function (str) {
        var match = real.exec.apply(this, arguments),
            name, r2;
        if (match) {
            // Fix browsers whose `exec` methods don't consistently return `undefined` for
            // nonparticipating capturing groups
            if (!compliantExecNpcg && match.length > 1 && indexOf(match, "") > -1) {
                r2 = RegExp(this.source, real.replace.call(getNativeFlags(this), "g", ""));
                // Using `str.slice(match.index)` rather than `match[0]` in case lookahead allowed
                // matching due to characters outside the match
                real.replace.call(str.slice(match.index), r2, function () {
                    for (var i = 1; i < arguments.length - 2; i++) {
                        if (arguments[i] === undefined)
                            match[i] = undefined;
                    }
                });
            }
            // Attach named capture properties
            if (this._xregexp && this._xregexp.captureNames) {
                for (var i = 1; i < match.length; i++) {
                    name = this._xregexp.captureNames[i - 1];
                    if (name)
                       match[name] = match[i];
                }
            }
            // Fix browsers that increment `lastIndex` after zero-length matches
            if (!compliantLastIndexIncrement && this.global && !match[0].length && (this.lastIndex > match.index))
                this.lastIndex--;
        }
        return match;
    };

    // Don't override `test` if it won't change anything
    if (!compliantLastIndexIncrement) {
        // Fix browser bug in native method
        RegExp.prototype.test = function (str) {
            // Use the native `exec` to skip some processing overhead, even though the overriden
            // `exec` would take care of the `lastIndex` fix
            var match = real.exec.call(this, str);
            // Fix browsers that increment `lastIndex` after zero-length matches
            if (match && this.global && !match[0].length && (this.lastIndex > match.index))
                this.lastIndex--;
            return !!match;
        };
    }

    // Adds named capture support and fixes browser bugs in native method
    String.prototype.match = function (regex) {
        if (!XRegExp.isRegExp(regex))
            regex = RegExp(regex); // Native `RegExp`
        if (regex.global) {
            var result = real.match.apply(this, arguments);
            regex.lastIndex = 0; // Fix IE bug
            return result;
        }
        return regex.exec(this); // Run the altered `exec`
    };

    // Adds support for `${n}` tokens for named and numbered backreferences in replacement text,
    // and provides named backreferences to replacement functions as `arguments[0].name`. Also
    // fixes cross-browser differences in replacement text syntax when performing a replacement
    // using a nonregex search value, and the value of replacement regexes' `lastIndex` property
    // during replacement iterations. Note that this doesn't support SpiderMonkey's proprietary
    // third (`flags`) parameter
    String.prototype.replace = function (search, replacement) {
        var isRegex = XRegExp.isRegExp(search),
            captureNames, result, str;
        // There are many combinations of search/replacement types/values and browser bugs that
        // preclude passing to native `replace`, so just keep this check relatively simple
        if (isRegex && typeof replacement.valueOf() === "string" && replacement.indexOf("${") === -1 && compliantLastIndexReset)
            return real.replace.apply(this, arguments);
        if (!isRegex)
            search = search + ""; // Type conversion
        else if (search._xregexp)
            captureNames = search._xregexp.captureNames; // Array or `null`

        if (typeof replacement === "function") {
            result = real.replace.call(this, search, function () {
                if (captureNames) {
                    // Change the `arguments[0]` string primitive to a String object which can store properties
                    arguments[0] = new String(arguments[0]);
                    // Store named backreferences on `arguments[0]`
                    for (var i = 0; i < captureNames.length; i++) {
                        if (captureNames[i])
                            arguments[0][captureNames[i]] = arguments[i + 1];
                    }
                }
                // Update `lastIndex` before calling `replacement`
                if (isRegex && search.global)
                    search.lastIndex = arguments[arguments.length - 2] + arguments[0].length;
                return replacement.apply(null, arguments);
            });
        } else {
            str = this + ""; // Type conversion, so `args[args.length - 1]` will be a string (given nonstring `this`)
            result = real.replace.call(str, search, function () {
                var args = arguments; // Keep this function's `arguments` available through closure
                return real.replace.call(replacement, replacementToken, function ($0, $1, $2) {
                    // Numbered backreference (without delimiters) or special variable
                    if ($1) {
                        switch ($1) {
                            case "$":return "$";
                            case "&":return args[0];
                            case "`":return args[args.length - 1].slice(0, args[args.length - 2]);
                            case "'":return args[args.length - 1].slice(args[args.length - 2] + args[0].length);
                            // Numbered backreference
                            default:
                                // What does "$10" mean?
                                // - Backreference 10, if 10 or more capturing groups exist
                                // - Backreference 1 followed by "0", if 1-9 capturing groups exist
                                // - Otherwise, it's the string "$10"
                                // Also note:
                                // - Backreferences cannot be more than two digits (enforced by `replacementToken`)
                                // - "$01" is equivalent to "$1" if a capturing group exists, otherwise it's the string "$01"
                                // - There is no "$0" token ("$&" is the entire match)
                                var literalNumbers = "";
                                $1 = +$1; // Type conversion; drop leading zero
                                if (!$1) // `$1` was "0" or "00"
                                    return $0;
                                while ($1 > args.length - 3) {
                                    literalNumbers = String.prototype.slice.call($1, -1) + literalNumbers;
                                    $1 = Math.floor($1 / 10); // Drop the last digit
                                }
                                return ($1 ? args[$1] || "" : "$") + literalNumbers;
                        }
                    // Named backreference or delimited numbered backreference
                    } else {
                        // What does "${n}" mean?
                        // - Backreference to numbered capture n. Two differences from "$n":
                        //   - n can be more than two digits
                        //   - Backreference 0 is allowed, and is the entire match
                        // - Backreference to named capture n, if it exists and is not a number overridden by numbered capture
                        // - Otherwise, it's the string "${n}"
                        var n = +$2; // Type conversion; drop leading zeros
                        if (n <= args.length - 3)
                            return args[n];
                        n = captureNames ? indexOf(captureNames, $2) : -1;
                        return n > -1 ? args[n + 1] : $0;
                    }
                });
            });
        }

        if (isRegex && search.global)
            search.lastIndex = 0; // Fix IE bug

        return result;
    };

    // A consistent cross-browser, ES3 compliant `split`
    String.prototype.split = function (s /* separator */, limit) {
        // If separator `s` is not a regex, use the native `split`
        if (!XRegExp.isRegExp(s))
            return real.split.apply(this, arguments);

        var str = this + "", // Type conversion
            output = [],
            lastLastIndex = 0,
            match, lastLength;

        // Behavior for `limit`: if it's...
        // - `undefined`: No limit
        // - `NaN` or zero: Return an empty array
        // - A positive number: Use `Math.floor(limit)`
        // - A negative number: No limit
        // - Other: Type-convert, then use the above rules
        if (limit === undefined || +limit < 0) {
            limit = Infinity;
        } else {
            limit = Math.floor(+limit);
            if (!limit)
                return [];
        }

        // This is required if not `s.global`, and it avoids needing to set `s.lastIndex` to zero
        // and restore it to its original value when we're done using the regex
        s = XRegExp.copyAsGlobal(s);

        while ((match = s.exec(str))) { // Run the altered `exec` (required for `lastIndex` fix, etc.)
            if (s.lastIndex > lastLastIndex) {
                output.push(str.slice(lastLastIndex, match.index));

                if (match.length > 1 && match.index < str.length)
                    Array.prototype.push.apply(output, match.slice(1));

                lastLength = match[0].length;
                lastLastIndex = s.lastIndex;

                if (output.length >= limit)
                    break;
            }

            if (s.lastIndex === match.index)
                s.lastIndex++;
        }

        if (lastLastIndex === str.length) {
            if (!real.test.call(s, "") || lastLength)
                output.push("");
        } else {
            output.push(str.slice(lastLastIndex));
        }

        return output.length > limit ? output.slice(0, limit) : output;
    };


    //---------------------------------
    //  Private helper functions
    //---------------------------------

    // Supporting function for `XRegExp`, `XRegExp.copyAsGlobal`, etc. Returns a copy of a `RegExp`
    // instance with a fresh `lastIndex` (set to zero), preserving properties required for named
    // capture. Also allows adding new flags in the process of copying the regex
    function clone (regex, additionalFlags) {
        if (!XRegExp.isRegExp(regex))
            throw TypeError("type RegExp expected");
        var x = regex._xregexp;
        regex = XRegExp(regex.source, getNativeFlags(regex) + (additionalFlags || ""));
        if (x) {
            regex._xregexp = {
                source: x.source,
                captureNames: x.captureNames ? x.captureNames.slice(0) : null
            };
        }
        return regex;
    }

    function getNativeFlags (regex) {
        return (regex.global     ? "g" : "") +
               (regex.ignoreCase ? "i" : "") +
               (regex.multiline  ? "m" : "") +
               (regex.extended   ? "x" : "") + // Proposed for ES4; included in AS3
               (regex.sticky     ? "y" : "");
    }

    function runTokens (pattern, index, scope, context) {
        var i = tokens.length,
            result, match, t;
        // Protect against constructing XRegExps within token handler and trigger functions
        isInsideConstructor = true;
        // Must reset `isInsideConstructor`, even if a `trigger` or `handler` throws
        try {
            while (i--) { // Run in reverse order
                t = tokens[i];
                if ((scope & t.scope) && (!t.trigger || t.trigger.call(context))) {
                    t.pattern.lastIndex = index;
                    match = t.pattern.exec(pattern); // Running the altered `exec` here allows use of named backreferences, etc.
                    if (match && match.index === index) {
                        result = {
                            output: t.handler.call(context, match, scope),
                            match: match
                        };
                        break;
                    }
                }
            }
        } catch (err) {
            throw err;
        } finally {
            isInsideConstructor = false;
        }
        return result;
    }

    function indexOf (array, item, from) {
        if (Array.prototype.indexOf) // Use the native array method if available
            return array.indexOf(item, from);
        for (var i = from || 0; i < array.length; i++) {
            if (array[i] === item)
                return i;
        }
        return -1;
    }


    //---------------------------------
    //  Built-in tokens
    //---------------------------------

    // Augment XRegExp's regular expression syntax and flags. Note that when adding tokens, the
    // third (`scope`) argument defaults to `XRegExp.OUTSIDE_CLASS`

    // Comment pattern: (?# )
    XRegExp.addToken(
        /\(\?#[^)]*\)/,
        function (match) {
            // Keep tokens separated unless the following token is a quantifier
            return real.test.call(quantifier, match.input.slice(match.index + match[0].length)) ? "" : "(?:)";
        }
    );

    // Capturing group (match the opening parenthesis only).
    // Required for support of named capturing groups
    XRegExp.addToken(
        /\((?!\?)/,
        function () {
            this.captureNames.push(null);
            return "(";
        }
    );

    // Named capturing group (match the opening delimiter only): (?<name>
    XRegExp.addToken(
        /\(\?<([$\w]+)>/,
        function (match) {
            this.captureNames.push(match[1]);
            this.hasNamedCapture = true;
            return "(";
        }
    );

    // Named backreference: \k<name>
    XRegExp.addToken(
        /\\k<([\w$]+)>/,
        function (match) {
            var index = indexOf(this.captureNames, match[1]);
            // Keep backreferences separate from subsequent literal numbers. Preserve back-
            // references to named groups that are undefined at this point as literal strings
            return index > -1 ?
                "\\" + (index + 1) + (isNaN(match.input.charAt(match.index + match[0].length)) ? "" : "(?:)") :
                match[0];
        }
    );

    // Empty character class: [] or [^]
    XRegExp.addToken(
        /\[\^?]/,
        function (match) {
            // For cross-browser compatibility with ES3, convert [] to \b\B and [^] to [\s\S].
            // (?!) should work like \b\B, but is unreliable in Firefox
            return match[0] === "[]" ? "\\b\\B" : "[\\s\\S]";
        }
    );

    // Mode modifier at the start of the pattern only, with any combination of flags imsx: (?imsx)
    // Does not support x(?i), (?-i), (?i-m), (?i: ), (?i)(?m), etc.
    XRegExp.addToken(
        /^\(\?([imsx]+)\)/,
        function (match) {
            this.setFlag(match[1]);
            return "";
        }
    );

    // Whitespace and comments, in free-spacing (aka extended) mode only
    XRegExp.addToken(
        /(?:\s+|#.*)+/,
        function (match) {
            // Keep tokens separated unless the following token is a quantifier
            return real.test.call(quantifier, match.input.slice(match.index + match[0].length)) ? "" : "(?:)";
        },
        XRegExp.OUTSIDE_CLASS,
        function () {return this.hasFlag("x");}
    );

    // Dot, in dotall (aka singleline) mode only
    XRegExp.addToken(
        /\./,
        function () {return "[\\s\\S]";},
        XRegExp.OUTSIDE_CLASS,
        function () {return this.hasFlag("s");}
    );


    //---------------------------------
    //  Backward compatibility
    //---------------------------------

    // Uncomment the following block for compatibility with XRegExp 1.0-1.2:
    /*
    XRegExp.matchWithinChain = XRegExp.matchChain;
    RegExp.prototype.addFlags = function (s) {return clone(this, s);};
    RegExp.prototype.execAll = function (s) {var r = []; XRegExp.iterate(s, this, function (m) {r.push(m);}); return r;};
    RegExp.prototype.forEachExec = function (s, f, c) {return XRegExp.iterate(s, this, f, c);};
    RegExp.prototype.validate = function (s) {var r = RegExp("^(?:" + this.source + ")$(?!\\s)", getNativeFlags(this)); if (this.global) this.lastIndex = 0; return s.search(r) === 0;};
    */

})();



/*
XRegExp Unicode plugin base 0.5
(c) 2008-2010 Steven Levithan
MIT License
<http://xregexp.com>
Uses the Unicode 5.2 character database

The Unicode plugin base adds support for the \p{L} token only (Unicode category Letter). Plugin
packages are available that add support for the remaining Unicode categories, as well as Unicode
scripts and blocks.

All Unicode tokens can be inverted by using an uppercase P; e.g., \P{L} matches any character not
in Unicode's Letter category. Negated Unicode tokens are not supported within character classes.

Letter case, spaces, hyphens, and underscores are ignored when comparing Unicode token names.
*/

// var XRegExp; // Brett: already above

if (!XRegExp) {
    throw ReferenceError("XRegExp must be loaded before the Unicode plugin");
}

(function () {

    var unicode = {}; // protected storage for package tokens

    XRegExp.addUnicodePackage = function (pack) {
        var codePoint = /\w{4}/g,
            clip = /[- _]+/g,
            name, p;
        for (p in pack) {
            if (pack.hasOwnProperty(p)) {
                name = p.replace(clip, "").toLowerCase();
                // disallow overriding properties that have already been added
                if (!unicode.hasOwnProperty(name)) {
                    unicode[name] = pack[p].replace(codePoint, "\\u$&");
                }
            }
        }
    };

    XRegExp.addToken(
        /\\([pP]){(\^?)([^}]*)}/,
        function (match, scope) {
            var negated = (match[1] === "P" || match[2]),
                item = match[3].replace(/[- _]+/g, "").toLowerCase();

            // \p{}, \P{}, and \p{^} are valid, but the double negative \P{^} isn't
            if (match[1] === "P" && match[2])
                throw SyntaxError("erroneous characters: " + match[0]);
            if (negated && scope === XRegExp.INSIDE_CLASS)
                throw SyntaxError("not supported in character classes: \\" + match[1] + "{" + match[2] + "...}");
            if (!unicode.hasOwnProperty(item))
                throw SyntaxError("invalid or unsupported Unicode item: " + match[0]);

            return scope === XRegExp.OUTSIDE_CLASS ?
                "[" + (negated ? "^" : "") + unicode[item] + "]" :
                unicode[item];
        },
        XRegExp.INSIDE_CLASS | XRegExp.OUTSIDE_CLASS
    );

    XRegExp.addUnicodePackage({
        L: "0041-005A0061-007A00AA00B500BA00C0-00D600D8-00F600F8-02C102C6-02D102E0-02E402EC02EE0370-037403760377037A-037D03860388-038A038C038E-03A103A3-03F503F7-0481048A-05250531-055605590561-058705D0-05EA05F0-05F20621-064A066E066F0671-06D306D506E506E606EE06EF06FA-06FC06FF07100712-072F074D-07A507B107CA-07EA07F407F507FA0800-0815081A082408280904-0939093D09500958-0961097109720979-097F0985-098C098F09900993-09A809AA-09B009B209B6-09B909BD09CE09DC09DD09DF-09E109F009F10A05-0A0A0A0F0A100A13-0A280A2A-0A300A320A330A350A360A380A390A59-0A5C0A5E0A72-0A740A85-0A8D0A8F-0A910A93-0AA80AAA-0AB00AB20AB30AB5-0AB90ABD0AD00AE00AE10B05-0B0C0B0F0B100B13-0B280B2A-0B300B320B330B35-0B390B3D0B5C0B5D0B5F-0B610B710B830B85-0B8A0B8E-0B900B92-0B950B990B9A0B9C0B9E0B9F0BA30BA40BA8-0BAA0BAE-0BB90BD00C05-0C0C0C0E-0C100C12-0C280C2A-0C330C35-0C390C3D0C580C590C600C610C85-0C8C0C8E-0C900C92-0CA80CAA-0CB30CB5-0CB90CBD0CDE0CE00CE10D05-0D0C0D0E-0D100D12-0D280D2A-0D390D3D0D600D610D7A-0D7F0D85-0D960D9A-0DB10DB3-0DBB0DBD0DC0-0DC60E01-0E300E320E330E40-0E460E810E820E840E870E880E8A0E8D0E94-0E970E99-0E9F0EA1-0EA30EA50EA70EAA0EAB0EAD-0EB00EB20EB30EBD0EC0-0EC40EC60EDC0EDD0F000F40-0F470F49-0F6C0F88-0F8B1000-102A103F1050-1055105A-105D106110651066106E-10701075-1081108E10A0-10C510D0-10FA10FC1100-1248124A-124D1250-12561258125A-125D1260-1288128A-128D1290-12B012B2-12B512B8-12BE12C012C2-12C512C8-12D612D8-13101312-13151318-135A1380-138F13A0-13F41401-166C166F-167F1681-169A16A0-16EA1700-170C170E-17111720-17311740-17511760-176C176E-17701780-17B317D717DC1820-18771880-18A818AA18B0-18F51900-191C1950-196D1970-19741980-19AB19C1-19C71A00-1A161A20-1A541AA71B05-1B331B45-1B4B1B83-1BA01BAE1BAF1C00-1C231C4D-1C4F1C5A-1C7D1CE9-1CEC1CEE-1CF11D00-1DBF1E00-1F151F18-1F1D1F20-1F451F48-1F4D1F50-1F571F591F5B1F5D1F5F-1F7D1F80-1FB41FB6-1FBC1FBE1FC2-1FC41FC6-1FCC1FD0-1FD31FD6-1FDB1FE0-1FEC1FF2-1FF41FF6-1FFC2071207F2090-209421022107210A-211321152119-211D212421262128212A-212D212F-2139213C-213F2145-2149214E218321842C00-2C2E2C30-2C5E2C60-2CE42CEB-2CEE2D00-2D252D30-2D652D6F2D80-2D962DA0-2DA62DA8-2DAE2DB0-2DB62DB8-2DBE2DC0-2DC62DC8-2DCE2DD0-2DD62DD8-2DDE2E2F300530063031-3035303B303C3041-3096309D-309F30A1-30FA30FC-30FF3105-312D3131-318E31A0-31B731F0-31FF3400-4DB54E00-9FCBA000-A48CA4D0-A4FDA500-A60CA610-A61FA62AA62BA640-A65FA662-A66EA67F-A697A6A0-A6E5A717-A71FA722-A788A78BA78CA7FB-A801A803-A805A807-A80AA80C-A822A840-A873A882-A8B3A8F2-A8F7A8FBA90A-A925A930-A946A960-A97CA984-A9B2A9CFAA00-AA28AA40-AA42AA44-AA4BAA60-AA76AA7AAA80-AAAFAAB1AAB5AAB6AAB9-AABDAAC0AAC2AADB-AADDABC0-ABE2AC00-D7A3D7B0-D7C6D7CB-D7FBF900-FA2DFA30-FA6DFA70-FAD9FB00-FB06FB13-FB17FB1DFB1F-FB28FB2A-FB36FB38-FB3CFB3EFB40FB41FB43FB44FB46-FBB1FBD3-FD3DFD50-FD8FFD92-FDC7FDF0-FDFBFE70-FE74FE76-FEFCFF21-FF3AFF41-FF5AFF66-FFBEFFC2-FFC7FFCA-FFCFFFD2-FFD7FFDA-FFDC"
    });

})();

// STATIC VARIABLES (CONSTANTS)
var _emptyparenth = '\\s*\\(\\s*\\)', // our own convenience "class"
    _strSeparator = ';',
    _PredefinedEntityRef = '&(?:lt|gt|apos|quot|amp);',
    _Digits = '\\d+',
    _HexDigits = '[\\da-fA-F]+',
    _CharRef = '&#' + _Digits + ';|&#x' + _HexDigits + ';',
    _EscapeQuot = '""',
    _EscapeApos = '\'\'',
    _StringLiteral = '(?:"'+
                                        '(?:' +
                                            _PredefinedEntityRef + '|' + _CharRef + '|' + _EscapeQuot + '|' + '[^"&]*?'+
                                        ')*' +
                                    '")?|(?:\''+
                                        '(?:' +
                                            _PredefinedEntityRef + '|' + _CharRef + '|' + _EscapeApos  + '|' + '[^"&]*?'+
                                        ')*' +
                                    '\')?',
    // From Namespaces 1.0
    // The first is not an official EBNF class
    _NameStartCharNoColon = 'A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u0200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\ud800-\udb7f\udc00-\udfff', // The last two ranges are for surrogates that comprise #x10000-#xEFFFF
    _NameStartChar = ':' + _NameStartCharNoColon,
    _NameChar = '.0-9\u00B7\u0300-\u036F\u203F-\u2040-', // Don't need escaping since to be put in a character class
    _NCName = '[' + _NameStartCharNoColon + '][' + _NameChar + ']*',
//    _Name = '[' + _NameStartChar + '][' + _NameChar + ']*',
    _URILiteral = _StringLiteral,
    _LocalPart = _NCName,
    _Prefix = _NCName,
    _PrefixedName = _Prefix + ':' + _LocalPart,
    _UnprefixedName = _LocalPart,
    _QName = _PrefixedName + '|' + _UnprefixedName,
    _SchemaElementTest = '',
    _ElementTest = '',
    _DocumentTest = 'document-node\\s*\\(\\s*('+ _ElementTest + '|' + _SchemaElementTest + ')?\\s*\\)',
    _AttributeTest = '',
    _SchemaAttributeTest = '',
    _PITest = '',
    _CommentTest = 'comment' + _emptyparenth,
    _TextTest = 'text' + _emptyparenth,
    _NamespaceNodeTest = 'namespace-node' + _emptyparenth,
    _AnyKindTest = 'node' + _emptyparenth,
    _KindTest = _DocumentTest + '|' + _ElementTest + '|' + _AttributeTest + '|' + _SchemaElementTest + '|' + _SchemaAttributeTest + '|' + _PITest + '|' + _CommentTest + '|' + _TextTest + '|' + _NamespaceNodeTest + '|' + _AnyKindTest,
    _FunctionTest = '',
    _AtomicType = _QName,
    // _ParenthesizedItemType = '\\(\\s*' + _ItemType + '\\s*\\)', // Would be recursive
    _ItemType = _KindTest + '|item'+_emptyparenth + '|' + _FunctionTest + '|' + _AtomicType + '|', // has _ParenthesizedItemType at end too, but would be recursive definition
    _OccurrenceIndicator = '\\?|\\*|\\+',
    _SequenceType = '(?:empty-sequence'+_emptyparenth+'|' + _ItemType + '('+_OccurrenceIndicator + ')?)',
    _VarName = _QName,
    _TypeDeclaration = 'as\\s+' + _SequenceType,
    _PositionalVar = 'at\\s+$' + _VarName,
    _AllowingEmpty = 'allowing\\s+empty',
    _ForBinding = '$' + _VarName + '\\s+(?:' + _TypeDeclaration + '\\s+)?(?:' +
                                    _AllowingEmpty + '\\s+)?(?:' + _PositionalVar + '\\s+)?in\\s+', // has _ExprSingle at end too, but would be recursive definition
    _ForClause = 'for\\s+' + _ForBinding + '(\\s*,\\s*' + _ForBinding + ')*',
    _LetBinding = '$' + _VarName + '\\s+(?:' + _TypeDeclaration + '\\s+)?:=', // has _ExprSingle at end too, but would be recursive definition
    _LetClause = 'let\\s+' + _LetBinding + '(\\s*,\\s*' + _LetBinding + ')*',
    _CurrentItem = _QName,
    _PreviousItem = _QName,
    _NextItem = _QName,
    _WindowVars = '(?:$('+_CurrentItem+'))?\\s*(?:\\s+' + _PositionalVar + ')?(\\s+previous\\s+$'+_PreviousItem+
                                    ')?(\\s+next\\s+$' + _NextItem,
    _WindowStartCondition = 'start\\s+' + _WindowVars + '\\s+when\\s+', // has _ExprSingle at end too, but would be recursive definition
    _WindowEndCondition = '(only)?\\s+end\\s+' + _WindowVars + '\\s+when\\s+', // has _ExprSingle at end too, but would be recursive definition
    _TumblingWindowClause = 'tumbling\\s+window\\s+$' + _VarName + '\\s+(?:' + _TypeDeclaration + '\\s+)?in\\s+', // has _ExprSingle at end too, but would be recursive definition
    _endTumblingWindowClause = '\\s+'+_WindowStartCondition + '(?:\\s+' + _WindowEndCondition + ')?', // not a real class but needed after recursive portion
    _SlidingWindowClause = 'sliding\\s+window\\s+$' + _VarName + '\\s+(?:' + _TypeDeclaration + '\\s+)?in\\s+', // has _ExprSingle at end too, but would be recursive definition,
    _endSlidingWindowClause = '\\s+'+_WindowStartCondition + '\\s+' + _WindowEndCondition, // not a real class but needed after recursive portion
    _WindowClause = 'for\\s+(?:'+ _TumblingWindowClause + '|' + _SlidingWindowClause + ')',
    _InitialClause = _ForClause + '|' + _LetClause + '|' + _WindowClause,
    _CountClause = 'count\\s+$' + _VarName,
    _WhereClause = 'where\\s+', // has _ExprSingle at end too, but would be recursive definition
    _GroupingSpec = '$' + _VarName + '(\\s+collation\\s+'+_URILiteral+')?',
    _GroupingSpecList = _GroupingSpec + '(\\s*,\\s*'+_GroupingSpec+')*',
    _GroupByClause = 'group\\s+by\\s+' + _GroupingSpecList,
    _OrderByClause = '',
    _IntermediateClause = _InitialClause + '|' + _WhereClause + '|' + _GroupByClause + '|' + _OrderByClause + _CountClause,
    _ReturnClause = 'return\\s+', // has _ExprSingle at end too, but would be recursive definition
    _FLWORExpr = _InitialClause + '\\s*' + _IntermediateClause + '\\s*' + _ReturnClause,
    _QuantifiedExpr = '',
    _SwitchExpr = '',
    _TypeswitchExpr = '',
    _IfExpr = '',
    _TryCatchExpr = '',
    _OrExpr = '',
    _ExprSingle = '(?:' + _FLWORExpr + '|' + _QuantifiedExpr + '|' + _SwitchExpr + '|' + _TypeswitchExpr + '|' +
                                _IfExpr + '|' + _TryCatchExpr + '|' + _OrExpr + ')',
    _Expr = _ExprSingle + '(\\s*,\\s*' + _ExprSingle + ')*',
    _EnclosedExpr = '\\{\\s*' + _Expr +  '\\s*\\}',
    _FunctionBody = _EnclosedExpr,
    _Param = '$' + _QName + '(?:\\s+' + _TypeDeclaration + ')?',
    _ParamList = _Param + '(\\s*,\\s*' + _Param + ')*',
    _PrivateOption = 'private|public',
    _DeterministicOption = 'deterministic|nondeterministic',
    _FunctionOptions = '(\\s*'+_PrivateOption+'|\\s*'+_DeterministicOption+')*', // Allows only one of each, but we'll follow spec's EBNF as allows for specific error on multiple options
    _VarValue = _ExprSingle, // XQuery 1.1
    _VarDefaultValue = _ExprSingle, // XQuery 1.1
    _DFPropertyName=  'decimal-separator|grouping-separator|infinity|minus-sign|NaN|percent|per-mille|zero-digit|digit|pattern-separator',
    _PreserveMode = 'preserve|no-preserve',
    _InheritMode = 'inherit|no-inherit',
    _EOFError = 'EOF reached with no library or main module',
    _defaultFunctionNamespace = 'http://www.w3.org/2005/xpath-functions',
    _XMLNamespace = 'http://www.w3.org/XML/1998/namespace',
    _xmlnsNamespace = 'http://www.w3.org/2000/xmlns/';



/*
XRegExp Unicode plugin pack: Categories 1.0
(c) 2010 Steven Levithan
MIT License
<http://xregexp.com>
Uses the Unicode 5.2 character database

This package for the XRegExp Unicode plugin enables the following Unicode categories (aka properties):

L - Letter (the top-level Letter category is included in the Unicode plugin base script)
	Ll - Lowercase letter
	Lu - Uppercase letter
	Lt - Titlecase letter
	Lm - Modifier letter
	Lo - Letter without case
M - Mark
	Mn - Non-spacing mark
	Mc - Spacing combining mark
	Me - Enclosing mark
N - Number
	Nd - Decimal digit
	Nl - Letter number
	No -  Other number
P - Punctuation
	Pd - Dash punctuation
	Ps - Open punctuation
	Pe - Close punctuation
	Pi - Initial punctuation
	Pf - Final punctuation
	Pc - Connector punctuation
	Po - Other punctuation
S - Symbol
	Sm - Math symbol
	Sc - Currency symbol
	Sk - Modifier symbol
	So - Other symbol
Z - Separator
	Zs - Space separator
	Zl - Line separator
	Zp - Paragraph separator
C - Other
	Cc - Control
	Cf - Format
	Co - Private use
	Cs - Surrogate
	Cn - Unassigned

Example usage:

	\p{N}
	\p{Cn}
*/

// var XRegExp; // Brett: already above

if (!(XRegExp && XRegExp.addUnicodePackage)) {
	throw ReferenceError("XRegExp's Unicode plugin must be loaded before adding categories");
}

XRegExp.addUnicodePackage({
	//L: "", // included in the Unicode plugin base script
	Ll: "0061-007A00AA00B500BA00DF-00F600F8-00FF01010103010501070109010B010D010F01110113011501170119011B011D011F01210123012501270129012B012D012F01310133013501370138013A013C013E014001420144014601480149014B014D014F01510153015501570159015B015D015F01610163016501670169016B016D016F0171017301750177017A017C017E-0180018301850188018C018D019201950199-019B019E01A101A301A501A801AA01AB01AD01B001B401B601B901BA01BD-01BF01C601C901CC01CE01D001D201D401D601D801DA01DC01DD01DF01E101E301E501E701E901EB01ED01EF01F001F301F501F901FB01FD01FF02010203020502070209020B020D020F02110213021502170219021B021D021F02210223022502270229022B022D022F02310233-0239023C023F0240024202470249024B024D024F-02930295-02AF037103730377037B-037D039003AC-03CE03D003D103D5-03D703D903DB03DD03DF03E103E303E503E703E903EB03ED03EF-03F303F503F803FB03FC0430-045F04610463046504670469046B046D046F04710473047504770479047B047D047F0481048B048D048F04910493049504970499049B049D049F04A104A304A504A704A904AB04AD04AF04B104B304B504B704B904BB04BD04BF04C204C404C604C804CA04CC04CE04CF04D104D304D504D704D904DB04DD04DF04E104E304E504E704E904EB04ED04EF04F104F304F504F704F904FB04FD04FF05010503050505070509050B050D050F05110513051505170519051B051D051F0521052305250561-05871D00-1D2B1D62-1D771D79-1D9A1E011E031E051E071E091E0B1E0D1E0F1E111E131E151E171E191E1B1E1D1E1F1E211E231E251E271E291E2B1E2D1E2F1E311E331E351E371E391E3B1E3D1E3F1E411E431E451E471E491E4B1E4D1E4F1E511E531E551E571E591E5B1E5D1E5F1E611E631E651E671E691E6B1E6D1E6F1E711E731E751E771E791E7B1E7D1E7F1E811E831E851E871E891E8B1E8D1E8F1E911E931E95-1E9D1E9F1EA11EA31EA51EA71EA91EAB1EAD1EAF1EB11EB31EB51EB71EB91EBB1EBD1EBF1EC11EC31EC51EC71EC91ECB1ECD1ECF1ED11ED31ED51ED71ED91EDB1EDD1EDF1EE11EE31EE51EE71EE91EEB1EED1EEF1EF11EF31EF51EF71EF91EFB1EFD1EFF-1F071F10-1F151F20-1F271F30-1F371F40-1F451F50-1F571F60-1F671F70-1F7D1F80-1F871F90-1F971FA0-1FA71FB0-1FB41FB61FB71FBE1FC2-1FC41FC61FC71FD0-1FD31FD61FD71FE0-1FE71FF2-1FF41FF61FF7210A210E210F2113212F21342139213C213D2146-2149214E21842C30-2C5E2C612C652C662C682C6A2C6C2C712C732C742C76-2C7C2C812C832C852C872C892C8B2C8D2C8F2C912C932C952C972C992C9B2C9D2C9F2CA12CA32CA52CA72CA92CAB2CAD2CAF2CB12CB32CB52CB72CB92CBB2CBD2CBF2CC12CC32CC52CC72CC92CCB2CCD2CCF2CD12CD32CD52CD72CD92CDB2CDD2CDF2CE12CE32CE42CEC2CEE2D00-2D25A641A643A645A647A649A64BA64DA64FA651A653A655A657A659A65BA65DA65FA663A665A667A669A66BA66DA681A683A685A687A689A68BA68DA68FA691A693A695A697A723A725A727A729A72BA72DA72F-A731A733A735A737A739A73BA73DA73FA741A743A745A747A749A74BA74DA74FA751A753A755A757A759A75BA75DA75FA761A763A765A767A769A76BA76DA76FA771-A778A77AA77CA77FA781A783A785A787A78CFB00-FB06FB13-FB17FF41-FF5A",
	Lu: "0041-005A00C0-00D600D8-00DE01000102010401060108010A010C010E01100112011401160118011A011C011E01200122012401260128012A012C012E01300132013401360139013B013D013F0141014301450147014A014C014E01500152015401560158015A015C015E01600162016401660168016A016C016E017001720174017601780179017B017D018101820184018601870189-018B018E-0191019301940196-0198019C019D019F01A001A201A401A601A701A901AC01AE01AF01B1-01B301B501B701B801BC01C401C701CA01CD01CF01D101D301D501D701D901DB01DE01E001E201E401E601E801EA01EC01EE01F101F401F6-01F801FA01FC01FE02000202020402060208020A020C020E02100212021402160218021A021C021E02200222022402260228022A022C022E02300232023A023B023D023E02410243-02460248024A024C024E03700372037603860388-038A038C038E038F0391-03A103A3-03AB03CF03D2-03D403D803DA03DC03DE03E003E203E403E603E803EA03EC03EE03F403F703F903FA03FD-042F04600462046404660468046A046C046E04700472047404760478047A047C047E0480048A048C048E04900492049404960498049A049C049E04A004A204A404A604A804AA04AC04AE04B004B204B404B604B804BA04BC04BE04C004C104C304C504C704C904CB04CD04D004D204D404D604D804DA04DC04DE04E004E204E404E604E804EA04EC04EE04F004F204F404F604F804FA04FC04FE05000502050405060508050A050C050E05100512051405160518051A051C051E0520052205240531-055610A0-10C51E001E021E041E061E081E0A1E0C1E0E1E101E121E141E161E181E1A1E1C1E1E1E201E221E241E261E281E2A1E2C1E2E1E301E321E341E361E381E3A1E3C1E3E1E401E421E441E461E481E4A1E4C1E4E1E501E521E541E561E581E5A1E5C1E5E1E601E621E641E661E681E6A1E6C1E6E1E701E721E741E761E781E7A1E7C1E7E1E801E821E841E861E881E8A1E8C1E8E1E901E921E941E9E1EA01EA21EA41EA61EA81EAA1EAC1EAE1EB01EB21EB41EB61EB81EBA1EBC1EBE1EC01EC21EC41EC61EC81ECA1ECC1ECE1ED01ED21ED41ED61ED81EDA1EDC1EDE1EE01EE21EE41EE61EE81EEA1EEC1EEE1EF01EF21EF41EF61EF81EFA1EFC1EFE1F08-1F0F1F18-1F1D1F28-1F2F1F38-1F3F1F48-1F4D1F591F5B1F5D1F5F1F68-1F6F1FB8-1FBB1FC8-1FCB1FD8-1FDB1FE8-1FEC1FF8-1FFB21022107210B-210D2110-211221152119-211D212421262128212A-212D2130-2133213E213F214521832C00-2C2E2C602C62-2C642C672C692C6B2C6D-2C702C722C752C7E-2C802C822C842C862C882C8A2C8C2C8E2C902C922C942C962C982C9A2C9C2C9E2CA02CA22CA42CA62CA82CAA2CAC2CAE2CB02CB22CB42CB62CB82CBA2CBC2CBE2CC02CC22CC42CC62CC82CCA2CCC2CCE2CD02CD22CD42CD62CD82CDA2CDC2CDE2CE02CE22CEB2CEDA640A642A644A646A648A64AA64CA64EA650A652A654A656A658A65AA65CA65EA662A664A666A668A66AA66CA680A682A684A686A688A68AA68CA68EA690A692A694A696A722A724A726A728A72AA72CA72EA732A734A736A738A73AA73CA73EA740A742A744A746A748A74AA74CA74EA750A752A754A756A758A75AA75CA75EA760A762A764A766A768A76AA76CA76EA779A77BA77DA77EA780A782A784A786A78BFF21-FF3A",
	Lt: "01C501C801CB01F21F88-1F8F1F98-1F9F1FA8-1FAF1FBC1FCC1FFC",
	Lm: "02B0-02C102C6-02D102E0-02E402EC02EE0374037A0559064006E506E607F407F507FA081A0824082809710E460EC610FC17D718431AA71C78-1C7D1D2C-1D611D781D9B-1DBF2071207F2090-20942C7D2D6F2E2F30053031-3035303B309D309E30FC-30FEA015A4F8-A4FDA60CA67FA717-A71FA770A788A9CFAA70AADDFF70FF9EFF9F",
	Lo: "01BB01C0-01C3029405D0-05EA05F0-05F20621-063F0641-064A066E066F0671-06D306D506EE06EF06FA-06FC06FF07100712-072F074D-07A507B107CA-07EA0800-08150904-0939093D09500958-096109720979-097F0985-098C098F09900993-09A809AA-09B009B209B6-09B909BD09CE09DC09DD09DF-09E109F009F10A05-0A0A0A0F0A100A13-0A280A2A-0A300A320A330A350A360A380A390A59-0A5C0A5E0A72-0A740A85-0A8D0A8F-0A910A93-0AA80AAA-0AB00AB20AB30AB5-0AB90ABD0AD00AE00AE10B05-0B0C0B0F0B100B13-0B280B2A-0B300B320B330B35-0B390B3D0B5C0B5D0B5F-0B610B710B830B85-0B8A0B8E-0B900B92-0B950B990B9A0B9C0B9E0B9F0BA30BA40BA8-0BAA0BAE-0BB90BD00C05-0C0C0C0E-0C100C12-0C280C2A-0C330C35-0C390C3D0C580C590C600C610C85-0C8C0C8E-0C900C92-0CA80CAA-0CB30CB5-0CB90CBD0CDE0CE00CE10D05-0D0C0D0E-0D100D12-0D280D2A-0D390D3D0D600D610D7A-0D7F0D85-0D960D9A-0DB10DB3-0DBB0DBD0DC0-0DC60E01-0E300E320E330E40-0E450E810E820E840E870E880E8A0E8D0E94-0E970E99-0E9F0EA1-0EA30EA50EA70EAA0EAB0EAD-0EB00EB20EB30EBD0EC0-0EC40EDC0EDD0F000F40-0F470F49-0F6C0F88-0F8B1000-102A103F1050-1055105A-105D106110651066106E-10701075-1081108E10D0-10FA1100-1248124A-124D1250-12561258125A-125D1260-1288128A-128D1290-12B012B2-12B512B8-12BE12C012C2-12C512C8-12D612D8-13101312-13151318-135A1380-138F13A0-13F41401-166C166F-167F1681-169A16A0-16EA1700-170C170E-17111720-17311740-17511760-176C176E-17701780-17B317DC1820-18421844-18771880-18A818AA18B0-18F51900-191C1950-196D1970-19741980-19AB19C1-19C71A00-1A161A20-1A541B05-1B331B45-1B4B1B83-1BA01BAE1BAF1C00-1C231C4D-1C4F1C5A-1C771CE9-1CEC1CEE-1CF12135-21382D30-2D652D80-2D962DA0-2DA62DA8-2DAE2DB0-2DB62DB8-2DBE2DC0-2DC62DC8-2DCE2DD0-2DD62DD8-2DDE3006303C3041-3096309F30A1-30FA30FF3105-312D3131-318E31A0-31B731F0-31FF3400-4DB54E00-9FCBA000-A014A016-A48CA4D0-A4F7A500-A60BA610-A61FA62AA62BA66EA6A0-A6E5A7FB-A801A803-A805A807-A80AA80C-A822A840-A873A882-A8B3A8F2-A8F7A8FBA90A-A925A930-A946A960-A97CA984-A9B2AA00-AA28AA40-AA42AA44-AA4BAA60-AA6FAA71-AA76AA7AAA80-AAAFAAB1AAB5AAB6AAB9-AABDAAC0AAC2AADBAADCABC0-ABE2AC00-D7A3D7B0-D7C6D7CB-D7FBF900-FA2DFA30-FA6DFA70-FAD9FB1DFB1F-FB28FB2A-FB36FB38-FB3CFB3EFB40FB41FB43FB44FB46-FBB1FBD3-FD3DFD50-FD8FFD92-FDC7FDF0-FDFBFE70-FE74FE76-FEFCFF66-FF6FFF71-FF9DFFA0-FFBEFFC2-FFC7FFCA-FFCFFFD2-FFD7FFDA-FFDC",
	M:  "0300-036F0483-04890591-05BD05BF05C105C205C405C505C70610-061A064B-065E067006D6-06DC06DE-06E406E706E806EA-06ED07110730-074A07A6-07B007EB-07F30816-0819081B-08230825-08270829-082D0900-0903093C093E-094E0951-0955096209630981-098309BC09BE-09C409C709C809CB-09CD09D709E209E30A01-0A030A3C0A3E-0A420A470A480A4B-0A4D0A510A700A710A750A81-0A830ABC0ABE-0AC50AC7-0AC90ACB-0ACD0AE20AE30B01-0B030B3C0B3E-0B440B470B480B4B-0B4D0B560B570B620B630B820BBE-0BC20BC6-0BC80BCA-0BCD0BD70C01-0C030C3E-0C440C46-0C480C4A-0C4D0C550C560C620C630C820C830CBC0CBE-0CC40CC6-0CC80CCA-0CCD0CD50CD60CE20CE30D020D030D3E-0D440D46-0D480D4A-0D4D0D570D620D630D820D830DCA0DCF-0DD40DD60DD8-0DDF0DF20DF30E310E34-0E3A0E47-0E4E0EB10EB4-0EB90EBB0EBC0EC8-0ECD0F180F190F350F370F390F3E0F3F0F71-0F840F860F870F90-0F970F99-0FBC0FC6102B-103E1056-1059105E-10601062-10641067-106D1071-10741082-108D108F109A-109D135F1712-17141732-1734175217531772177317B6-17D317DD180B-180D18A91920-192B1930-193B19B0-19C019C819C91A17-1A1B1A55-1A5E1A60-1A7C1A7F1B00-1B041B34-1B441B6B-1B731B80-1B821BA1-1BAA1C24-1C371CD0-1CD21CD4-1CE81CED1CF21DC0-1DE61DFD-1DFF20D0-20F02CEF-2CF12DE0-2DFF302A-302F3099309AA66F-A672A67CA67DA6F0A6F1A802A806A80BA823-A827A880A881A8B4-A8C4A8E0-A8F1A926-A92DA947-A953A980-A983A9B3-A9C0AA29-AA36AA43AA4CAA4DAA7BAAB0AAB2-AAB4AAB7AAB8AABEAABFAAC1ABE3-ABEAABECABEDFB1EFE00-FE0FFE20-FE26",
	Mn: "0300-036F0483-04870591-05BD05BF05C105C205C405C505C70610-061A064B-065E067006D6-06DC06DF-06E406E706E806EA-06ED07110730-074A07A6-07B007EB-07F30816-0819081B-08230825-08270829-082D0900-0902093C0941-0948094D0951-095509620963098109BC09C1-09C409CD09E209E30A010A020A3C0A410A420A470A480A4B-0A4D0A510A700A710A750A810A820ABC0AC1-0AC50AC70AC80ACD0AE20AE30B010B3C0B3F0B41-0B440B4D0B560B620B630B820BC00BCD0C3E-0C400C46-0C480C4A-0C4D0C550C560C620C630CBC0CBF0CC60CCC0CCD0CE20CE30D41-0D440D4D0D620D630DCA0DD2-0DD40DD60E310E34-0E3A0E47-0E4E0EB10EB4-0EB90EBB0EBC0EC8-0ECD0F180F190F350F370F390F71-0F7E0F80-0F840F860F870F90-0F970F99-0FBC0FC6102D-10301032-10371039103A103D103E10581059105E-10601071-1074108210851086108D109D135F1712-17141732-1734175217531772177317B7-17BD17C617C9-17D317DD180B-180D18A91920-19221927192819321939-193B1A171A181A561A58-1A5E1A601A621A65-1A6C1A73-1A7C1A7F1B00-1B031B341B36-1B3A1B3C1B421B6B-1B731B801B811BA2-1BA51BA81BA91C2C-1C331C361C371CD0-1CD21CD4-1CE01CE2-1CE81CED1DC0-1DE61DFD-1DFF20D0-20DC20E120E5-20F02CEF-2CF12DE0-2DFF302A-302F3099309AA66FA67CA67DA6F0A6F1A802A806A80BA825A826A8C4A8E0-A8F1A926-A92DA947-A951A980-A982A9B3A9B6-A9B9A9BCAA29-AA2EAA31AA32AA35AA36AA43AA4CAAB0AAB2-AAB4AAB7AAB8AABEAABFAAC1ABE5ABE8ABEDFB1EFE00-FE0FFE20-FE26",
	Mc: "0903093E-09400949-094C094E0982098309BE-09C009C709C809CB09CC09D70A030A3E-0A400A830ABE-0AC00AC90ACB0ACC0B020B030B3E0B400B470B480B4B0B4C0B570BBE0BBF0BC10BC20BC6-0BC80BCA-0BCC0BD70C01-0C030C41-0C440C820C830CBE0CC0-0CC40CC70CC80CCA0CCB0CD50CD60D020D030D3E-0D400D46-0D480D4A-0D4C0D570D820D830DCF-0DD10DD8-0DDF0DF20DF30F3E0F3F0F7F102B102C10311038103B103C105610571062-10641067-106D108310841087-108C108F109A-109C17B617BE-17C517C717C81923-19261929-192B193019311933-193819B0-19C019C819C91A19-1A1B1A551A571A611A631A641A6D-1A721B041B351B3B1B3D-1B411B431B441B821BA11BA61BA71BAA1C24-1C2B1C341C351CE11CF2A823A824A827A880A881A8B4-A8C3A952A953A983A9B4A9B5A9BAA9BBA9BD-A9C0AA2FAA30AA33AA34AA4DAA7BABE3ABE4ABE6ABE7ABE9ABEAABEC",
	Me: "0488048906DE20DD-20E020E2-20E4A670-A672",
	N:  "0030-003900B200B300B900BC-00BE0660-066906F0-06F907C0-07C90966-096F09E6-09EF09F4-09F90A66-0A6F0AE6-0AEF0B66-0B6F0BE6-0BF20C66-0C6F0C78-0C7E0CE6-0CEF0D66-0D750E50-0E590ED0-0ED90F20-0F331040-10491090-10991369-137C16EE-16F017E0-17E917F0-17F91810-18191946-194F19D0-19DA1A80-1A891A90-1A991B50-1B591BB0-1BB91C40-1C491C50-1C5920702074-20792080-20892150-21822185-21892460-249B24EA-24FF2776-27932CFD30073021-30293038-303A3192-31953220-32293251-325F3280-328932B1-32BFA620-A629A6E6-A6EFA830-A835A8D0-A8D9A900-A909A9D0-A9D9AA50-AA59ABF0-ABF9FF10-FF19",
	Nd: "0030-00390660-066906F0-06F907C0-07C90966-096F09E6-09EF0A66-0A6F0AE6-0AEF0B66-0B6F0BE6-0BEF0C66-0C6F0CE6-0CEF0D66-0D6F0E50-0E590ED0-0ED90F20-0F291040-10491090-109917E0-17E91810-18191946-194F19D0-19DA1A80-1A891A90-1A991B50-1B591BB0-1BB91C40-1C491C50-1C59A620-A629A8D0-A8D9A900-A909A9D0-A9D9AA50-AA59ABF0-ABF9FF10-FF19",
	Nl: "16EE-16F02160-21822185-218830073021-30293038-303AA6E6-A6EF",
	No: "00B200B300B900BC-00BE09F4-09F90BF0-0BF20C78-0C7E0D70-0D750F2A-0F331369-137C17F0-17F920702074-20792080-20892150-215F21892460-249B24EA-24FF2776-27932CFD3192-31953220-32293251-325F3280-328932B1-32BFA830-A835",
	P:  "0021-00230025-002A002C-002F003A003B003F0040005B-005D005F007B007D00A100AB00B700BB00BF037E0387055A-055F0589058A05BE05C005C305C605F305F40609060A060C060D061B061E061F066A-066D06D40700-070D07F7-07F90830-083E0964096509700DF40E4F0E5A0E5B0F04-0F120F3A-0F3D0F850FD0-0FD4104A-104F10FB1361-13681400166D166E169B169C16EB-16ED1735173617D4-17D617D8-17DA1800-180A1944194519DE19DF1A1E1A1F1AA0-1AA61AA8-1AAD1B5A-1B601C3B-1C3F1C7E1C7F1CD32010-20272030-20432045-20512053-205E207D207E208D208E2329232A2768-277527C527C627E6-27EF2983-299829D8-29DB29FC29FD2CF9-2CFC2CFE2CFF2E00-2E2E2E302E313001-30033008-30113014-301F3030303D30A030FBA4FEA4FFA60D-A60FA673A67EA6F2-A6F7A874-A877A8CEA8CFA8F8-A8FAA92EA92FA95FA9C1-A9CDA9DEA9DFAA5C-AA5FAADEAADFABEBFD3EFD3FFE10-FE19FE30-FE52FE54-FE61FE63FE68FE6AFE6BFF01-FF03FF05-FF0AFF0C-FF0FFF1AFF1BFF1FFF20FF3B-FF3DFF3FFF5BFF5DFF5F-FF65",
	Pd: "002D058A05BE140018062010-20152E172E1A301C303030A0FE31FE32FE58FE63FF0D",
	Ps: "0028005B007B0F3A0F3C169B201A201E2045207D208D23292768276A276C276E27702772277427C527E627E827EA27EC27EE2983298529872989298B298D298F299129932995299729D829DA29FC2E222E242E262E283008300A300C300E3010301430163018301A301DFD3EFE17FE35FE37FE39FE3BFE3DFE3FFE41FE43FE47FE59FE5BFE5DFF08FF3BFF5BFF5FFF62",
	Pe: "0029005D007D0F3B0F3D169C2046207E208E232A2769276B276D276F27712773277527C627E727E927EB27ED27EF298429862988298A298C298E2990299229942996299829D929DB29FD2E232E252E272E293009300B300D300F3011301530173019301B301E301FFD3FFE18FE36FE38FE3AFE3CFE3EFE40FE42FE44FE48FE5AFE5CFE5EFF09FF3DFF5DFF60FF63",
	Pi: "00AB2018201B201C201F20392E022E042E092E0C2E1C2E20",
	Pf: "00BB2019201D203A2E032E052E0A2E0D2E1D2E21",
	Pc: "005F203F20402054FE33FE34FE4D-FE4FFF3F",
	Po: "0021-00230025-0027002A002C002E002F003A003B003F0040005C00A100B700BF037E0387055A-055F058905C005C305C605F305F40609060A060C060D061B061E061F066A-066D06D40700-070D07F7-07F90830-083E0964096509700DF40E4F0E5A0E5B0F04-0F120F850FD0-0FD4104A-104F10FB1361-1368166D166E16EB-16ED1735173617D4-17D617D8-17DA1800-18051807-180A1944194519DE19DF1A1E1A1F1AA0-1AA61AA8-1AAD1B5A-1B601C3B-1C3F1C7E1C7F1CD3201620172020-20272030-2038203B-203E2041-20432047-205120532055-205E2CF9-2CFC2CFE2CFF2E002E012E06-2E082E0B2E0E-2E162E182E192E1B2E1E2E1F2E2A-2E2E2E302E313001-3003303D30FBA4FEA4FFA60D-A60FA673A67EA6F2-A6F7A874-A877A8CEA8CFA8F8-A8FAA92EA92FA95FA9C1-A9CDA9DEA9DFAA5C-AA5FAADEAADFABEBFE10-FE16FE19FE30FE45FE46FE49-FE4CFE50-FE52FE54-FE57FE5F-FE61FE68FE6AFE6BFF01-FF03FF05-FF07FF0AFF0CFF0EFF0FFF1AFF1BFF1FFF20FF3CFF61FF64FF65",
	S:  "0024002B003C-003E005E0060007C007E00A2-00A900AC00AE-00B100B400B600B800D700F702C2-02C502D2-02DF02E5-02EB02ED02EF-02FF03750384038503F604820606-0608060B060E060F06E906FD06FE07F609F209F309FA09FB0AF10B700BF3-0BFA0C7F0CF10CF20D790E3F0F01-0F030F13-0F170F1A-0F1F0F340F360F380FBE-0FC50FC7-0FCC0FCE0FCF0FD5-0FD8109E109F13601390-139917DB194019E0-19FF1B61-1B6A1B74-1B7C1FBD1FBF-1FC11FCD-1FCF1FDD-1FDF1FED-1FEF1FFD1FFE20442052207A-207C208A-208C20A0-20B8210021012103-21062108210921142116-2118211E-2123212521272129212E213A213B2140-2144214A-214D214F2190-2328232B-23E82400-24262440-244A249C-24E92500-26CD26CF-26E126E326E8-26FF2701-27042706-2709270C-27272729-274B274D274F-27522756-275E2761-276727942798-27AF27B1-27BE27C0-27C427C7-27CA27CC27D0-27E527F0-29822999-29D729DC-29FB29FE-2B4C2B50-2B592CE5-2CEA2E80-2E992E9B-2EF32F00-2FD52FF0-2FFB300430123013302030363037303E303F309B309C319031913196-319F31C0-31E33200-321E322A-32503260-327F328A-32B032C0-32FE3300-33FF4DC0-4DFFA490-A4C6A700-A716A720A721A789A78AA828-A82BA836-A839AA77-AA79FB29FDFCFDFDFE62FE64-FE66FE69FF04FF0BFF1C-FF1EFF3EFF40FF5CFF5EFFE0-FFE6FFE8-FFEEFFFCFFFD",
	Sm: "002B003C-003E007C007E00AC00B100D700F703F60606-060820442052207A-207C208A-208C2140-2144214B2190-2194219A219B21A021A321A621AE21CE21CF21D221D421F4-22FF2308-230B23202321237C239B-23B323DC-23E125B725C125F8-25FF266F27C0-27C427C7-27CA27CC27D0-27E527F0-27FF2900-29822999-29D729DC-29FB29FE-2AFF2B30-2B442B47-2B4CFB29FE62FE64-FE66FF0BFF1C-FF1EFF5CFF5EFFE2FFE9-FFEC",
	Sc: "002400A2-00A5060B09F209F309FB0AF10BF90E3F17DB20A0-20B8A838FDFCFE69FF04FFE0FFE1FFE5FFE6",
	Sk: "005E006000A800AF00B400B802C2-02C502D2-02DF02E5-02EB02ED02EF-02FF0375038403851FBD1FBF-1FC11FCD-1FCF1FDD-1FDF1FED-1FEF1FFD1FFE309B309CA700-A716A720A721A789A78AFF3EFF40FFE3",
	So: "00A600A700A900AE00B000B60482060E060F06E906FD06FE07F609FA0B700BF3-0BF80BFA0C7F0CF10CF20D790F01-0F030F13-0F170F1A-0F1F0F340F360F380FBE-0FC50FC7-0FCC0FCE0FCF0FD5-0FD8109E109F13601390-1399194019E0-19FF1B61-1B6A1B74-1B7C210021012103-21062108210921142116-2118211E-2123212521272129212E213A213B214A214C214D214F2195-2199219C-219F21A121A221A421A521A7-21AD21AF-21CD21D021D121D321D5-21F32300-2307230C-231F2322-2328232B-237B237D-239A23B4-23DB23E2-23E82400-24262440-244A249C-24E92500-25B625B8-25C025C2-25F72600-266E2670-26CD26CF-26E126E326E8-26FF2701-27042706-2709270C-27272729-274B274D274F-27522756-275E2761-276727942798-27AF27B1-27BE2800-28FF2B00-2B2F2B452B462B50-2B592CE5-2CEA2E80-2E992E9B-2EF32F00-2FD52FF0-2FFB300430123013302030363037303E303F319031913196-319F31C0-31E33200-321E322A-32503260-327F328A-32B032C0-32FE3300-33FF4DC0-4DFFA490-A4C6A828-A82BA836A837A839AA77-AA79FDFDFFE4FFE8FFEDFFEEFFFCFFFD",
	Z:  "002000A01680180E2000-200A20282029202F205F3000",
	Zs: "002000A01680180E2000-200A202F205F3000",
	Zl: "2028",
	Zp: "2029",
	C:  "0000-001F007F-009F00AD03780379037F-0383038B038D03A20526-05300557055805600588058B-059005C8-05CF05EB-05EF05F5-0605061C061D0620065F06DD070E070F074B074C07B2-07BF07FB-07FF082E082F083F-08FF093A093B094F095609570973-097809800984098D098E0991099209A909B109B3-09B509BA09BB09C509C609C909CA09CF-09D609D8-09DB09DE09E409E509FC-0A000A040A0B-0A0E0A110A120A290A310A340A370A3A0A3B0A3D0A43-0A460A490A4A0A4E-0A500A52-0A580A5D0A5F-0A650A76-0A800A840A8E0A920AA90AB10AB40ABA0ABB0AC60ACA0ACE0ACF0AD1-0ADF0AE40AE50AF00AF2-0B000B040B0D0B0E0B110B120B290B310B340B3A0B3B0B450B460B490B4A0B4E-0B550B58-0B5B0B5E0B640B650B72-0B810B840B8B-0B8D0B910B96-0B980B9B0B9D0BA0-0BA20BA5-0BA70BAB-0BAD0BBA-0BBD0BC3-0BC50BC90BCE0BCF0BD1-0BD60BD8-0BE50BFB-0C000C040C0D0C110C290C340C3A-0C3C0C450C490C4E-0C540C570C5A-0C5F0C640C650C70-0C770C800C810C840C8D0C910CA90CB40CBA0CBB0CC50CC90CCE-0CD40CD7-0CDD0CDF0CE40CE50CF00CF3-0D010D040D0D0D110D290D3A-0D3C0D450D490D4E-0D560D58-0D5F0D640D650D76-0D780D800D810D840D97-0D990DB20DBC0DBE0DBF0DC7-0DC90DCB-0DCE0DD50DD70DE0-0DF10DF5-0E000E3B-0E3E0E5C-0E800E830E850E860E890E8B0E8C0E8E-0E930E980EA00EA40EA60EA80EA90EAC0EBA0EBE0EBF0EC50EC70ECE0ECF0EDA0EDB0EDE-0EFF0F480F6D-0F700F8C-0F8F0F980FBD0FCD0FD9-0FFF10C6-10CF10FD-10FF1249124E124F12571259125E125F1289128E128F12B112B612B712BF12C112C612C712D7131113161317135B-135E137D-137F139A-139F13F5-13FF169D-169F16F1-16FF170D1715-171F1737-173F1754-175F176D17711774-177F17B417B517DE17DF17EA-17EF17FA-17FF180F181A-181F1878-187F18AB-18AF18F6-18FF191D-191F192C-192F193C-193F1941-1943196E196F1975-197F19AC-19AF19CA-19CF19DB-19DD1A1C1A1D1A5F1A7D1A7E1A8A-1A8F1A9A-1A9F1AAE-1AFF1B4C-1B4F1B7D-1B7F1BAB-1BAD1BBA-1BFF1C38-1C3A1C4A-1C4C1C80-1CCF1CF3-1CFF1DE7-1DFC1F161F171F1E1F1F1F461F471F4E1F4F1F581F5A1F5C1F5E1F7E1F7F1FB51FC51FD41FD51FDC1FF01FF11FF51FFF200B-200F202A-202E2060-206F20722073208F2095-209F20B9-20CF20F1-20FF218A-218F23E9-23FF2427-243F244B-245F26CE26E226E4-26E727002705270A270B2728274C274E2753-2755275F27602795-279727B027BF27CB27CD-27CF2B4D-2B4F2B5A-2BFF2C2F2C5F2CF2-2CF82D26-2D2F2D66-2D6E2D70-2D7F2D97-2D9F2DA72DAF2DB72DBF2DC72DCF2DD72DDF2E32-2E7F2E9A2EF4-2EFF2FD6-2FEF2FFC-2FFF3040309730983100-3104312E-3130318F31B8-31BF31E4-31EF321F32FF4DB6-4DBF9FCC-9FFFA48D-A48FA4C7-A4CFA62C-A63FA660A661A674-A67BA698-A69FA6F8-A6FFA78D-A7FAA82C-A82FA83A-A83FA878-A87FA8C5-A8CDA8DA-A8DFA8FC-A8FFA954-A95EA97D-A97FA9CEA9DA-A9DDA9E0-A9FFAA37-AA3FAA4EAA4FAA5AAA5BAA7C-AA7FAAC3-AADAAAE0-ABBFABEEABEFABFA-ABFFD7A4-D7AFD7C7-D7CAD7FC-F8FFFA2EFA2FFA6EFA6FFADA-FAFFFB07-FB12FB18-FB1CFB37FB3DFB3FFB42FB45FBB2-FBD2FD40-FD4FFD90FD91FDC8-FDEFFDFEFDFFFE1A-FE1FFE27-FE2FFE53FE67FE6C-FE6FFE75FEFD-FF00FFBF-FFC1FFC8FFC9FFD0FFD1FFD8FFD9FFDD-FFDFFFE7FFEF-FFFBFFFEFFFF",
	Cc: "0000-001F007F-009F",
	Cf: "00AD0600-060306DD070F17B417B5200B-200F202A-202E2060-2064206A-206FFEFFFFF9-FFFB",
	Co: "E000-F8FF",
	Cs: "D800-DFFF",
	Cn: "03780379037F-0383038B038D03A20526-05300557055805600588058B-059005C8-05CF05EB-05EF05F5-05FF06040605061C061D0620065F070E074B074C07B2-07BF07FB-07FF082E082F083F-08FF093A093B094F095609570973-097809800984098D098E0991099209A909B109B3-09B509BA09BB09C509C609C909CA09CF-09D609D8-09DB09DE09E409E509FC-0A000A040A0B-0A0E0A110A120A290A310A340A370A3A0A3B0A3D0A43-0A460A490A4A0A4E-0A500A52-0A580A5D0A5F-0A650A76-0A800A840A8E0A920AA90AB10AB40ABA0ABB0AC60ACA0ACE0ACF0AD1-0ADF0AE40AE50AF00AF2-0B000B040B0D0B0E0B110B120B290B310B340B3A0B3B0B450B460B490B4A0B4E-0B550B58-0B5B0B5E0B640B650B72-0B810B840B8B-0B8D0B910B96-0B980B9B0B9D0BA0-0BA20BA5-0BA70BAB-0BAD0BBA-0BBD0BC3-0BC50BC90BCE0BCF0BD1-0BD60BD8-0BE50BFB-0C000C040C0D0C110C290C340C3A-0C3C0C450C490C4E-0C540C570C5A-0C5F0C640C650C70-0C770C800C810C840C8D0C910CA90CB40CBA0CBB0CC50CC90CCE-0CD40CD7-0CDD0CDF0CE40CE50CF00CF3-0D010D040D0D0D110D290D3A-0D3C0D450D490D4E-0D560D58-0D5F0D640D650D76-0D780D800D810D840D97-0D990DB20DBC0DBE0DBF0DC7-0DC90DCB-0DCE0DD50DD70DE0-0DF10DF5-0E000E3B-0E3E0E5C-0E800E830E850E860E890E8B0E8C0E8E-0E930E980EA00EA40EA60EA80EA90EAC0EBA0EBE0EBF0EC50EC70ECE0ECF0EDA0EDB0EDE-0EFF0F480F6D-0F700F8C-0F8F0F980FBD0FCD0FD9-0FFF10C6-10CF10FD-10FF1249124E124F12571259125E125F1289128E128F12B112B612B712BF12C112C612C712D7131113161317135B-135E137D-137F139A-139F13F5-13FF169D-169F16F1-16FF170D1715-171F1737-173F1754-175F176D17711774-177F17DE17DF17EA-17EF17FA-17FF180F181A-181F1878-187F18AB-18AF18F6-18FF191D-191F192C-192F193C-193F1941-1943196E196F1975-197F19AC-19AF19CA-19CF19DB-19DD1A1C1A1D1A5F1A7D1A7E1A8A-1A8F1A9A-1A9F1AAE-1AFF1B4C-1B4F1B7D-1B7F1BAB-1BAD1BBA-1BFF1C38-1C3A1C4A-1C4C1C80-1CCF1CF3-1CFF1DE7-1DFC1F161F171F1E1F1F1F461F471F4E1F4F1F581F5A1F5C1F5E1F7E1F7F1FB51FC51FD41FD51FDC1FF01FF11FF51FFF2065-206920722073208F2095-209F20B9-20CF20F1-20FF218A-218F23E9-23FF2427-243F244B-245F26CE26E226E4-26E727002705270A270B2728274C274E2753-2755275F27602795-279727B027BF27CB27CD-27CF2B4D-2B4F2B5A-2BFF2C2F2C5F2CF2-2CF82D26-2D2F2D66-2D6E2D70-2D7F2D97-2D9F2DA72DAF2DB72DBF2DC72DCF2DD72DDF2E32-2E7F2E9A2EF4-2EFF2FD6-2FEF2FFC-2FFF3040309730983100-3104312E-3130318F31B8-31BF31E4-31EF321F32FF4DB6-4DBF9FCC-9FFFA48D-A48FA4C7-A4CFA62C-A63FA660A661A674-A67BA698-A69FA6F8-A6FFA78D-A7FAA82C-A82FA83A-A83FA878-A87FA8C5-A8CDA8DA-A8DFA8FC-A8FFA954-A95EA97D-A97FA9CEA9DA-A9DDA9E0-A9FFAA37-AA3FAA4EAA4FAA5AAA5BAA7C-AA7FAAC3-AADAAAE0-ABBFABEEABEFABFA-ABFFD7A4-D7AFD7C7-D7CAD7FC-D7FFFA2EFA2FFA6EFA6FFADA-FAFFFB07-FB12FB18-FB1CFB37FB3DFB3FFB42FB45FBB2-FBD2FD40-FD4FFD90FD91FDC8-FDEFFDFEFDFFFE1A-FE1FFE27-FE2FFE53FE67FE6C-FE6FFE75FEFDFEFEFF00FFBF-FFC1FFC8FFC9FFD0FFD1FFD8FFD9FFDD-FFDFFFE7FFEF-FFF8FFFEFFFF"
});


function _round (value, precision, mode) {
    // http://kevin.vanzonneveld.net
    // +   original by: Philip Peterson
    // +    revised by: Onno Marsman
    // +      input by: Greenseed
    // +    revised by: T.Wild
    // +      input by: meo
    // +      input by: William
    // +   bugfixed by: Brett Zamir (http://brett-zamir.me)
    // +      input by: Josep Sanz (http://www.ws3.es/)
    // +    revised by: Rafa? Kukawski (http://blog.kukawski.pl/)
    // %        note 1: Great work. Ideas for improvement:
    // %        note 1:  - code more compliant with developer guidelines
    // %        note 1:  - for implementing PHP constant arguments look at
    // %        note 1:  the pathinfo() function, it offers the greatest
    // %        note 1:  flexibility & compatibility possible
    // *     example 1: round(1241757, -3);
    // *     returns 1: 1242000
    // *     example 2: round(3.6);
    // *     returns 2: 4
    // *     example 3: round(2.835, 2);
    // *     returns 3: 2.84
    // *     example 4: round(1.1749999999999, 2);
    // *     returns 4: 1.17
    // *     example 5: round(58551.799999999996, 2);
    // *     returns 5: 58551.8

	var m, f, isHalf, sgn; // helper variables
	precision |= 0; // making sure precision is integer
	m = Math.pow(10, precision);
	value *= m;
	sgn = (value>0)|-(value<0); // sign of the number
	isHalf = value % 1 === 0.5 * sgn;
	f = Math.floor(value);

	if(isHalf){
		switch(mode){
			case 'PHP_ROUND_HALF_DOWN':
				value = f + (sgn < 0); // rounds .5 toward zero
				break;
			case 'PHP_ROUND_HALF_EVEN':
				value = f + (f % 2 * sgn); // rouds .5 towards the next even integer
				break;
			case 'PHP_ROUND_HALF_ODD':
				value = f + !(f % 2); // rounds .5 towards the next odd integer
				break;
			default:
				value = f + (sgn > 0); // rounds .5 away from zero
		}
	}

	return (isHalf ? value : Math.round(value)) / m;
}

function _getWholeChar (str, i, returnSurrogates) {
    i = i || 0;
    var code = str.charCodeAt(i);
    if (isNaN(code)) {
        return ''; // Position not found
    }
    if (code < 0xD800 || code > 0xDFFF) {
        return str.charAt(i);
    }
    if (0xD800 <= code && code <= 0xDBFF) { // High surrogate (could change last hex to 0xDB7F to treat high private surrogates as single characters)
        if (str.length <= (i+1))  {
            if (returnSurrogates) {
                return str.charAt(i);
            }
            throw 'High surrogate without following low surrogate';
        }
        var next = str.charCodeAt(i+1);
        if (0xDC00 > next || next > 0xDFFF) {
            if (returnSurrogates) {
                return str.charAt(i);
            }
            throw 'High surrogate without following low surrogate';
        }
        return str.charAt(i)+str.charAt(i+1);
    }
    // Low surrogate (0xDC00 <= code && code <= 0xDFFF)
    if (i === 0) {
        if (returnSurrogates) {
            return str.charAt(i);
        }
        throw 'Low surrogate without preceding high surrogate';
    }
    var prev = str.charCodeAt(i-1);
    if (0xD800 > prev || prev > 0xDBFF) { // (could change last hex to 0xDB7F to treat high private surrogates as single characters)
        if (returnSurrogates) {
            return str.charAt(i);
        }
        throw 'Low surrogate without preceding high surrogate';
    }
    return false; // We can pass over low surrogates now as the second component in a pair which we have already processed
}

function _fixedCharCodeAt (str, idx, returnSurrogates) {
    idx = idx || 0;
    var hi,
        low,
        code = str.charCodeAt(idx);
    if (0xD800 <= code && code <= 0xDBFF) { // High surrogate (could change last hex to 0xDB7F to treat high private surrogates as single characters)
        hi = code;
        low = str.charCodeAt(idx+1);
        if (isNaN(low)) {
            if (returnSurrogates) {
                return code;
            }
            throw 'High surrogate not followed by low surrogate';
        }
        return ((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000;
    }
    if (0xDC00 <= code && code <= 0xDFFF) { // Low surrogate
        if (returnSurrogates) {
            return code;
        }
        return false; // We'll return false here so we don't count twice
        /*
        hi = str.charCodeAt(idx-1);
        low = code;
        return ((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000;
        */
    }
    return code;
}

function _fixedFromCharCode (codePt) {
    if (codePt > 0xFFFF) {
        codePt -= 0x10000;
        return String.fromCharCode(0xD800 + (codePt >> 10), 0xDC00 +
(codePt & 0x3FF));
    }
    else {
        return String.fromCharCode(codePt);
    }
}

function _map (arr, cb) {
    for (var i = 0, arrl = arr.length; i < arrl; i++) {
        arr[i] = cb(arr[i]);
    }
    return arr;
}

// Function can also be used standalone
/**
 * @namespace This contains methods for translating Korean Hangul/Jamo, since these
 *                              are obtained programmatically and not through the Unicode (or Unihan) database
 */
var Hangul = (function () {

    // Private static
    var JAMO_L_TABLE = [
            'G', 'GG', 'N', 'D', 'DD', 'R', 'M', 'B', 'BB',
            'S', 'SS', '', 'J', 'JJ', 'C', 'K', 'T', 'P', 'H'
        ],
        JAMO_V_TABLE = [
            'A', 'AE', 'YA', 'YAE', 'EO', 'E', 'YEO', 'YE', 'O',
            'WA', 'WAE', 'OE', 'YO', 'U', 'WEO', 'WE', 'WI',
            'YU', 'EU', 'YI', 'I'
        ],
        JAMO_T_TABLE = [
            '', 'G', 'GG', 'GS', 'N', 'NJ', 'NH', 'D', 'L', 'LG', 'LM',
            'LB', 'LS', 'LT', 'LP', 'LH', 'M', 'B', 'BS',
            'S', 'SS', 'NG', 'J', 'C', 'K', 'T', 'P', 'H'
        ];
    var sBase = 0xAC00,
        lBase = 0x1100,
        vBase = 0x1161,
        tBase = 0x11A7,
        sCount = 11172,
        lCount = 19, // Not in use for decomposition
        vCount = 21,
        tCount = 28,
        nCount = vCount * tCount;

    function _getWholeCharAndIncrement (str, i) {
        var code = str.charCodeAt(i);
        if (0xD800 <= code && code <= 0xDBFF) { // High surrogate (could change last hex to 0xDB7F to treat high private surrogates as single characters)
            if (str.length <= (i+1))  {
                throw 'High surrogate without following low surrogate';
            }
            var next = str.charCodeAt(i+1);
            if (0xDC00 > next || next > 0xDFFF) {
                throw 'High surrogate without following low surrogate';
            }
            return [i+1, str.charAt(i)+str.charAt(i+1)];
        }
        else if (0xDC00 <= code && code <= 0xDFFF) { // Low surrogate
            if (i === 0) {
                throw 'Low surrogate without preceding high surrogate';
            }
            var prev = str.charCodeAt(i-1);
            if (0xD800 > prev || prev > 0xDBFF) { // (could change last hex to 0xDB7F to treat high private surrogates as single characters)
                throw 'Low surrogate without preceding high surrogate';
            }
            return false; // We can pass over low surrogates now as the second component in a pair which we have already processed
        }
        return [i, str.charAt(i)];
    }

    function Hangul () {}

    /**
     * Break up a Hangul syllable into its Jamo components
     * @param {String|Number} syllableCode Character or decimal code point for Hangul syllable to decompose
     * @returns {Number[|String]} An array of the numeric value of each component or a string if unchanged or if input was a string)
     */
    Hangul.decomposeHangul = function (syllableCode) {
        var retStr = false;
        if (typeof syllableCode === 'string') {
            syllableCode = _fixedCharCodeAt(syllableCode, 0, true);
            retStr = true;
        }
        var sIndex = syllableCode - sBase;
        if (sIndex < 0 || sIndex >= sCount) {
            return retStr ? _fixedFromCharCode(syllableCode) : syllableCode;
        }
        var result = [];
        var l = lBase + Math.floor(sIndex / nCount);
        var v = vBase + Math.floor((sIndex % nCount) / tCount);
        var t = tBase + sIndex % tCount;
        result.push(l, v);
        if (t != tBase) {result.push(t);}
        return (retStr) ? _map(result, _fixedFromCharCode).join('') : result;
    };

    /**
     * Break up a Hangul syllable recursively
     * @param {String|Number} syllables String possibly including Hangul syllables to decompose
     * @returns {Number[|String]} An array of the numeric value of each component or a string if unchanged or if input was a string)
     * @fix: I didn't find that this ever produced a different outcome than the non-recursive version
     */
    Hangul.decomposeHangulRecursively = function (syllables) {
        var out = '', s;
        for (var i = 0, syll = syllables.length; i < syll; i++) {
            if ((s = _getWholeChar(syllables, i, true)) === false) { // Avoid treating surrogate pairs as more than one character
                continue;
            }
            var d = Hangul.decomposeHangul(s);
            out += (s === d) ? s : Hangul.decomposeHangulRecursively(d);
        }
        return out;
    };

    /**
     *
     * @param {String[]} source
     */
    Hangul.composeHangul = function (source) {
        var len = source.length;
        if (len === 0) {return '';}
        var result = [];

        var start = 0;
        var startLast = _getWholeCharAndIncrement(source, start);
        start = startLast[0];
        var last = startLast[1];

        // copy first char
        result.push(last);

        for (var i = start+1; i < len; ++i) {
            var iCh = _getWholeCharAndIncrement(source, i);
            i = iCh[0];
            var ch = iCh[1];

            // 1. check to see if two current characters are L and V
            var lIndex = _fixedCharCodeAt(last) - lBase;
            if (0 <= lIndex && lIndex < lCount) {
                var vIndex = _fixedCharCodeAt(ch) - vBase;
                if (0 <= vIndex && vIndex < vCount) {
                    // make syllable of form LV
                    last = _fixedFromCharCode(sBase + (lIndex * vCount + vIndex) * tCount);
                    result[result.length-1] = last; // reset last
                    continue; // discard ch
                }
            }

            // 2. check to see if two current characters are LV and T
            var sIndex = _fixedCharCodeAt(last) - sBase;
            if (0 <= sIndex && sIndex < sCount && (sIndex % tCount) === 0) {
                var tIndex = _fixedCharCodeAt(ch) - tBase;
                if (0 < tIndex && tIndex < tCount) {
                    // make syllable of form LVT
                    last = _fixedFromCharCode(_fixedCharCodeAt(last) + tIndex);
                    result[result.length-1] = last; // reset last
                    continue; // discard ch
                }
            }
            // if neither case was true, just add the character
            last = ch;
            result.push(ch);
        }
        return result;
    };

    /**
     * Gets a Unicode character for the passed-in Hangul syllable name
     * @param {String} name The name of the syllable to find
     * @author Brett Zamir (others adapted directly from Unicode)
     * @returns {String|Boolean} False if invalid, or otherwise the Hangul character represented by
     *                                                      the supplied name
     */
    Hangul.getHangulFromName = function (name) {

        // Turn indices into individual Jamo characters
        var l, v, t, lIndex, vIndex, tIndex;
        var ptr = 1;

        // L (can be 1-2 in name length)
        if (name.charAt(0) === name.charAt(1)) { // All two-letter names are doubles
            lIndex = JAMO_L_TABLE.indexOf(name.substr(0, 2));
            ptr++;
        }
        else {
            lIndex = JAMO_L_TABLE.indexOf(name.substr(0, 1));
        }

        // V (can be 1-3 in name length)
        vIndex = JAMO_V_TABLE.indexOf(name.substr(ptr, 3));
        if (vIndex !== -1) {
            ptr += 3;
        }
        else {
            vIndex = JAMO_V_TABLE.indexOf(name.substr(ptr, 2));
            if (vIndex !== -1) {
                ptr += 2;
            }
            else {
                vIndex = JAMO_V_TABLE.indexOf(name.substr(ptr, 1));
                ptr += 1;
            }
        }

        // T (can be 1-2 in name length)
        tIndex = JAMO_T_TABLE.indexOf(name.substr(ptr, 2));
        if (tIndex !== -1) {
            ptr += 2;
        }
        else {
            tIndex = JAMO_T_TABLE.indexOf(name.substr(ptr, 1));
            ptr += 1;
        }
        if (lIndex === -1 || vIndex === -1 || (tIndex && ptr < name.length)) { // If an invalid Hangul syllable name was passed in
            return false;
        }

        l = Hangul.getJamoForIndex(lIndex, 'l');
        v = Hangul.getJamoForIndex(vIndex, 'v');

        // May only be LV (?)
        t = '';
        if (tIndex) {
            t = Hangul.getJamoForIndex(tIndex, 't');
        }

        // Join Jamo characters together
        var jamo = l+v+t;
        // Convert Jamo into composite Hangul syllable
        return Hangul.composeHangul(jamo).join('');
    };

    /**
     * Utility (could be adapted to accept the letter(s))
     * @param {String} index
     * @param {'l'|'v'|'t'} type
     */
    Hangul.getJamoForIndex = function (index, type) {
        switch(type) {
            case 'l':
                return String.fromCharCode(lBase+index);
            case 'v':
                return String.fromCharCode(vBase+index);
            case 't':
                return String.fromCharCode(tBase+index);
            default:
                throw 'Unexpected type passed to getJamoCodePointForName';
        }
    };

    Hangul.getHangulName = function (syllableCode) {
        // Adapted from Hangul Character Names: http://unicode.org/reports/tr15/#Hangul

        // Following numbered items, with minor changes are from http://www.unicode.org/versions/Unicode5.0.0/ch03.pdf
        // 1. Compute the index of the syllable:
        // SIndex = S - SBase
        var sIndex = syllableCode - sBase;
        // 2. If SIndex is in the range (0 ? SIndex < SCount), then compute the components as follows:
        // The operators ??and ??are as defined in Table A-3 in Appendix A, Notational Conventions.
        if (sIndex < 0 && sIndex >= sCount) {
            throw new Error('Not a hangul syllable '+syllableCode);
        }
        /*
        var l = lBase + Math.floor(sIndex / nCount);
        var v = vBase + Math.floor((sIndex % nCount) / tCount);
        var t = tBase + sIndex % tCount;
        */
        var l = Math.floor(sIndex / nCount);
        var v = Math.floor((sIndex % nCount) / tCount);
        var t = sIndex % tCount;
        return  JAMO_L_TABLE[l] + JAMO_V_TABLE[v] + JAMO_T_TABLE[t];

        // 3. If T = TBase, then there is no trailing character, so replace S by the sequence
        // L V. Otherwise, there is a trailing character, so replace S by the sequence L V T.
        // Example. Compute the components:
        // L = LBase + 17
        // V = VBase + 16
        // T = TBase + 15
        // and replace the syllable by the sequence of components:
        // 0xD4DB => 0x1111, 0x1171, 0x11B6
        /*
        var arr = [l, v];
        if (t !== tBase) {
            arr.push(t);
        }
        // The character names for Hangul syllables are derived from the decomposition by starting
        // with the string hangul syllable, and appending the short name of each decomposition
        // component in order.
        for (var c=0; c < arr.length; c++) {
            var jamoComponent = getJamo(arr[c]);
            cjkText += jamoComponent;
        }
        */
    };
    return Hangul;
}());


/**
 * @param {String} picture A picture indicating the desired formatting
 * @param {String} tests An array of regular expressions of alternate digit ranges (minus initial and closing parentheses)
 */
function _getZeroOfDigitCategory (picture, tests) {
    testLoop : for (var i = 0, tl = tests.length; i < tl; i++) {
        var test = tests[i];
        var testRegex = new RegExp('^(' + test + ')'); // We only need one
        var match = picture.match(testRegex);
        if (!match) {
            continue;
        }
        var zeroes = test.split(/-.(\)\|\()?/);
        var zeroPtr = 0;
        while (!match[zeroPtr+1]) {
            if (!zeroes[zeroPtr]) { // Exhausted this regex's possibilities
                continue testLoop;
            }
            zeroPtr++;
        }
        return zeroes[zeroPtr];
    }
}

// SUPPORTING CLASSES (ERRORS)

function XQueryDynamicError (code, description, error_object) {
    this.code = code;
    this.description = this.message = description; // Also assign to 'message' for JS-familiar behavior
    this['error-object'] = this.error_object = error_object; // Allow either hyphenated or our own JS-friendly underscored form
}
XQueryDynamicError.prototype.toString = function () {
    return this.description;
};


function XPathXQueryFunctionsOperatorsError (code, msg) {
    this.message = 'err:' + code + ': ' + msg;
    this.code = code;
}
XPathXQueryFunctionsOperatorsError.prototype.toString = function() {
    return this.message;
};

/**
 * @param {String} code The XQuery code string
 * @param {String} msg The message to be displayed upon an error
 */
function XQueryError (code, msg) {
    this.message = 'err:' + code + ': ' + msg;
    this.code = code;
    // this.type = type; //  Might add argument or switch for whether static, dynamic, or type error (or move msg to switch too)
}
XQueryError.prototype.toString = function() {
    return this.message;
};

function EndOfInputException () {
    this.message = 'EndOfInputException';
}
EndOfInputException.prototype.toString = function() {
    return this.message;
};


/**
 * Thrown when an unexpected token is found
 * @param {String} token The unexpected token
 */
function UnexpectedToken (token) {
    this.token = token;
    this.message = 'Unexpected token ' + token;
}
UnexpectedToken.prototype.toString = function() {
    return this.message;
};



function anyURI (URI) {
    this.URI = URI;
}

XMLSchema = {};
XMLSchema.Types = {};
XMLSchema.Types.anyURI = anyURI;



XMLSchema.Types.QName = function (paramURI, paramQName) {
    // Fix: are these error conditions actually permitted under xs:QName() or only the calling function QName()?
    // Fix: this alone can be used for static context namespaces (?)
    var colonPos = paramQName.indexOf(':');
    if (
        (paramURI === '' || typeof paramURI === 'object' && paramURI.length === 0) &&
        colonPos !== -1
        ) {
        throw new XPathXQueryFunctionsOperatorsError('FOCA0002', 'Invalid lexical value');
    }
    if (!(new RegExp(_QName)).test(paramQName)) {
        throw new XPathXQueryFunctionsOperatorsError('FOCA0002', 'Invalid lexical value');
    }
    this.URI = new anyURI(paramURI);
    this.QName = paramQName;
    this.localName = colonPos === -1 ? paramQName : paramQName.slice(colonPos + 1);
    this.prefix = colonPos === -1 ? [] : paramQName.slice(0, colonPos);
};

function QName (paramURI, paramQName) {
    XMLSchema.Types.QName.call(this, paramURI, paramQName);
}
QName.prototype = new XMLSchema.Types.QName('', 'bogus');
QName.prototype.constructor = QName;
QName.prototype.toString = function () {
    throw 'Conversion of a QName to a string is not supported';
};




var XQueryAccessors = {
    'node-name' : function (node) {
        
    },
    nilled : function (node) {

    },
    string : function (item) {

    },
    data : function () {

    },
    'base-uri' : function (node) {

    },
    'document-uri' : function (node) {

    }
};

// Fix: Deal with type checking, all types of arguments; verify
// Fix: Allow underscored form?
var XQueryOperators = {
    // START NUMERIC OPERATORS
    // Arithmetic Operators on Numeric Values
    // Args are numeric and return numeric (except numeric-integer-divide which returns integer)
    'numeric-add' : function (arg1, arg2) {
        return arg1 + arg2;
    },
    'numeric-subtract' : function (arg1, arg2) {
        return arg1 - arg2;
    },
    'numeric-multiply' : function (arg1, arg2) {
        return arg1 * arg2;
    },
    'numeric-divide' : function (arg1, arg2) {
        return arg1 / arg2;
    },
    'numeric-integer-divide' : function (arg1, arg2) {
        return parseInt(arg1 / arg2, 10);
    },
    'numeric-mod' : function (arg1, arg2) {
        return arg1 % arg2;
    },
    'numeric-unary-plus' : function (arg1) {
        return +arg1;
    },
    'numeric-unary-minus' : function (arg1) {
        return -arg1;
    },
    // Comparison Operators on Numeric Values
    // args are numeric, and return booleans
    'numeric-equal' : function (arg1, arg2) {
        return arg1 === arg2;
    },
    'numeric-less-than' : function (arg1, arg2) {
        return arg1 < arg2;
    },
    'numeric-greater-than' : function (arg1, arg2) {
        return arg1 > arg2;
    },
    // END NUMERIC OPERATORS
    // START BOOLEAN OPERATORS
    // All take booleans as arguments and return booleans
    'boolean-equal' : function (value1, value2) {
        return value1 === value2;
    },
    'boolean-less-than' : function (arg1, arg2) {
        return !arg1 && arg2;
    },
    'boolean-greater-than' : function (arg1, arg2) {
        return arg1 && !arg2;
    },
    // END BOOLEAN OPERATORS
    // START DURATION OPERATORS
    // Comparison Operators on Durations
    // All return booleans
    'yearMonthDuration-less-than' : function () {

    },
    'yearMonthDuration-greater-than' : function () {

    },
    'dayTimeDuration-less-than' : function () {

    },
    'dayTimeDuration-greater-than' : function () {

    },
    'duration-equal' : function (arg1, arg2) {

    },
    // Arithmetic Operators on Durations
    'add-yearMonthDurations' : function (arg1, arg2) {

    },
    'subtract-yearMonthDurations' : function (arg1, arg2) {

    },
    'multiply-yearMonthDurations' : function (arg1, arg2) {

    },
    'divide-yearMonthDurations' : function (arg1, arg2) {

    },
    'divide-yearMonthDuration-by-yearMonthDuration' : function (arg1, arg2) {

    },
    'add-dayTimeDurations' : function (arg1, arg2) {

    },
    'subtract-dayTimeDurations' : function (arg1, arg2) {

    },
    'multiply-dayTimeDurations' : function (arg1, arg2) {

    },
    'divide-dayTimeDurations' : function (arg1, arg2) {

    },
    'divide-dayTimeDuration-by-dayTimeDuration' : function (arg1, arg2) {

    },
    // END DURATION OPERATORS
    // START DATE AND TIME OPERATORS
    // Comparison Operators on Duration, Date and Time Values
    // All return booleans
    'dateTime-equal' : function (arg1, arg2) {

    },
    'dateTime-less-than' : function (arg1, arg2) {

    },
    'dateTime-greater-than' : function (arg1, arg2) {

    },
    'date-equal' : function (arg1, arg2) {

    },
    'date-less-than' : function (arg1, arg2) {

    },
    'date-greater-than' : function (arg1, arg2) {

    },
    'time-equal' : function (arg1, arg2) {

    },
    'time-less-than' : function (arg1, arg2) {

    },
    'time-greater-than' : function (arg1, arg2) {

    },
    'gYearMonth-equal' : function (arg1, arg2) {

    },
    'gYear-equal' : function (arg1, arg2) {

    },
    'gMonthDay-equal' : function (arg1, arg2) {

    },
    'gMonth-equal' : function (arg1, arg2) {

    },
    'gDay-equal' : function (arg1, arg2) {

    },
    // Arithmetic Operators on Durations, Dates and Times
    'subtract-dateTimes' : function (arg1, arg2) {

    },
    'subtract-dates' : function (arg1, arg2) {

    },
    'subtract-times' : function (arg1, arg2) {

    },
    'add-yearMonthDuration-to-dateTime' : function (arg1, arg2) {
    
    },
    'add-dayTimeDuration-to-dateTime' : function (arg1, arg2) {

    },
    'subtract-yearMonthDuration-from-dateTime' : function (arg1, arg2) {

    },
    'subtract-dayTimeDuration-from-dateTime' : function (arg1, arg2) {

    },
    'add-yearMonthDuration-to-date' : function (arg1, arg2) {

    },
    'add-dayTimeDuration-to-date' : function (arg1, arg2) {

    },
    'subtract-yearMonthDuration-from-date' : function (arg1, arg2) {

    },
    'subtract-dayTimeDuration-from-date' : function (arg1, arg2) {

    },
    'add-dayTimeDuration-to-time' : function (arg1, arg2) {

    },
    'subtract-dayTimeDuration-from-time' : function (arg1, arg2) {

    },
    // END DATE AND TIME OPERATORS
    // START QNAME OPERATORS
    // Functions and Operators Related to QNames
    // Arguments are both QName
    'QName-equal' : function (arg1, arg2) { // returns boolean
        return arg1.URI.URI === arg2.URI.URI && // See XQueryFunctions['codepoint-equal']
                        arg1.localName === arg2.localName;
    },
    // END QNAME OPERATORS
    // START BINARY OPERATORS
    // Both return booleans
    'hexBinary-equal' : function (value1, value2) {
        
    },
    'base64Binary-equal' : function (value1, value2) {

    },
    // END BINARY OPERATORS
    // START NOTATION OPERATORS
    'NOTATION-equal' : function (arg1, arg2) { // returns boolean

    },
    // END NOTATION OPERATORS
    // START NODE OPERATORS
    // All take node() as arguments and return booleans
    'is-same-node' : function (arg1, arg2) {

    },
    'node-before' : function (arg1, arg2) {

    },
    'node-after' : function (arg1, arg2) {

    },    
    // END NODE OPERATORS
    // START SEQUENCE OPERATORS
    // General Functions and Operators on Sequences
    concatenate : function (seq1, seq2) {

    },
    // Equals, Union, Intersection and Except
    // All arguments and return values are node()*
    union : function (arg1, arg2) {
        
    },
    intersect : function (arg1, arg2) {

    },
    except : function (arg1, arg2) {

    },
    // Functions and Operators that Generate Sequences
    // All arguments are xs:integer and return values is xs:integer*
    to : function (firstval, lastval) {

    }
    // END SEQUENCE OPERATORS
};


function _toString (arg) {
    if (typeof arg === 'object' && arg.length === 0) {
        return '';
    }
    return arg.toString(); // Fix: Deal with all types if this is insufficient
}

// Fix: Deal with type checking, all types of arguments; verify
function XQueryFunctions () {
    this.trace = [];
}
// START ERRORS AND DIAGNOSTICS
XQueryFunctions.prototype.error = function (code, description, error_object) {
        if ((!code && !description && !error_object) || (typeof code === 'object' && code.length === 0)) {
            code = this.QName('http://www.w3.org/2005/xqt-errors', 'err:FOER0000');
        }
        throw XQueryDynamicError(code, description, error_object);
};
XQueryFunctions.prototype.trace = function (value, label) {
    this.trace.push({label:label, value:_toString(value)});
    return value;
};
// END ERRORS AND DIAGNOSTICS
// START NUMERIC FUNCTIONS
// Functions on Numeric Values
// All args here are numeric, with precision an integer, and
// all return values are numeric
XQueryFunctions.prototype.abs = function (arg) {
    return Math.abs(arg);
};
XQueryFunctions.prototype.ceiling = function (arg) {
    return Math.ceil(arg);
};
XQueryFunctions.prototype.floor = function (arg) {
    return Math.floor(arg);
};
XQueryFunctions.prototype.round = function (arg, precision) {
    return _round(arg, precision);
};
XQueryFunctions.prototype['round-half-to-even'] = function (arg, precision) {
    return _round(arg, precision, 'PHP_ROUND_HALF_EVEN');
};
// Trigonometrical Functions
// All args and return values here are double
XQueryFunctions.prototype.pi = function () {
    return Math.PI;
};
XQueryFunctions.prototype.sqrt = function (arg) {
    return Math.sqrt(arg);
};
XQueryFunctions.prototype.sin = function (arg) {
    return Math.sin(arg);
};
XQueryFunctions.prototype.cos = function (arg) {
    return Math.cos(arg);
};
XQueryFunctions.prototype.tan = function (arg) {
    return Math.tan(arg);
};
XQueryFunctions.prototype.asin = function (arg) {
    return Math.asin(arg);
};
XQueryFunctions.prototype.acos = function (arg) {
    return Math.acos(arg);
};
XQueryFunctions.prototype.atan = function (arg) {
    return Math.atan(arg);
};
// Formatting Integers
// Returns a string
XQueryFunctions.prototype['format-integer'] = function (value, picture, language) { // integer, string
    if (!value || (typeof value === 'object' && !value.length) || typeof value !== 'number') {
        return '';
    }
    language = language || this.language;

    var formatModifierPattern = '(t|o\\([^)]*\\)(,\\s*o\\([^)]*\\))*))';

    // Fix: Try regular modifiers here, including prepend '-' if negative


    var digitSeq = XRegExp('^\\p{Nd}+' + formatModifierPattern + '?$');
    // Fix: verify language supports format modifier if used (unless 't')
    if (digitSeq.test(picture)) {
        var minimumLength = this['string-length'](picture + ''); // Execute in case ever allows non-BMP
        var lt0 = value < 0;
        var valueLength = (value + '').length - (lt0 ? 1 : 0);
        if (valueLength < minimumLength) {
            var zero = _getZeroOfDigitCategory(picture, [ // Fix: The following might be obtained from the
                // XRegExp Unicode plugin's Nd category, if that property could be made public
                '\u0030-\u0039)|(\u0660-\u0669)|(\u06F0-\u06F9)|(\u07C0-\u07C9)|(\u0966-\u096F',
                '\u09E6-\u09EF)|(\u0A66-\u0A6F)|(\u0AE6-\u0AEF)|(\u0B66-\u0B6F)|(\u0BE6-\u0BEF',
                '\u0C66-\u0C6F)|(\u0CE6-\u0CEF)|(\u0D66-\u0D6F)|(\u0E50-\u0E59)|(\u0ED0-\u0ED9',
                '\u0F20-\u0F29)|(\u1040-\u1049)|(\u1090-\u1099)|(\u17E0-\u17E9)|(\u1810-\u1819',
                '\u1946-\u194F)|(\u19D0-\u19DA)|(\u1A80-\u1A89)|(\u1A90-\u1A99)|(\u1B50-\u1B59',
                '\u1BB0-\u1BB9)|(\u1C40-\u1C49)|(\u1C50-\u1C59)|(\uA620-\uA629)|(\uA8D0-\uA8D9',
                '\uA900-\uA909)|(\uA9D0-\uA9D9)|(\uAA50-\uAA59)|(\uABF0-\uABF9)|(\uFF10-\uFF19'
            ]);
            value = new Array(minimumLength - valueLength + 1).join(zero) + value;
        }
        return (lt0 ? '-' : '') + value;
    }
    // Cannot yet build in XRegExp a negated class for Nd, Nl, No, Lu, Ll, Lt, Lm and Lo
    var groupingSeps = '\\p{Mn}|\\p{Mc}|\\p{Me}|\\p{Pd}|\\p{Ps}|\\p{Pe}|\\p{Pi}|\\p{Pf}|\\p{Pc}|\\p{Po}|\\p{Sm}|\\p{Sc}|\\p{Sk}|\\p{So}|\\p{Zs}|\\p{Zl}|\\p{Zp}|\\p{Cc}|\\p{Cf}|\\p{Co}|\\p{Cs}|\\p{Cn}';
    var digitOrSepSeq = XRegExp(
        '^(?:\\p{Nd}|' +
        groupingSeps +
        ')+' +
        formatModifierPattern +
        '?$'
    );
    if (digitOrSepSeq.test(picture)) {
        var sep, sepHash = {}, sepSeq = [], sepIdxSeq = [];
        var groupingSepExpr = XRegExp(
            '(' + groupingSeps + ')'
        );
        while ((sep = groupingSepExpr.exec(picture)) != null) {
            if (!sepHash[sep]) {
                sepHash[sep] = true;
            }
            if (groupingSepExpr.lastIndex !== sepIdxSeq[0]) {
                sepHash[sep] = false;
            }

            sepIdxSeq.unshift(groupingSepExpr.lastIndex);
            sepSeq.unshift(sep);
        }

        var match = digitOrSepSeq.match(picture); // Must exist
        var idx = match[1] ? (picture.length - match[1].length) : picture.length;
        groupingSepExpr = XRegExp(
            '(' + groupingSeps + ')\\p{Nd}*$'
        );
        sep = groupingSepExpr[1]; // Must exist
        var newIdx;
        while ((newIdx = picture.lastIndexOf(sep, idx)) !== -1) {

        }
    }


    // Fix: add default (1) here if not matching above; prepend '-' if negative

};
// Formatting Numbers
// Returns a string
XQueryFunctions.prototype['format-number'] = function (value, picture, decimal_format_name) { // numeric, string, string

};
// END NUMERIC FUNCTIONS
// START STRING FUNCTIONS
// Functions to Assemble and Disassemble Strings
XQueryFunctions.prototype['codepoints-to-string'] = function (arg) {
    var str = '';
    for (var i = 0, argl = arg.length; i < argl; i++) {
        str += _fixedFromCharCode(i);
    }
    return str;
};
XQueryFunctions.prototype['string-to-codepoints'] = function (arg) {
    var output = [];
    for (var c, i = 0, argl = arg.length; i < argl; i++) {
        if ((c = _getWholeChar(arg, i)) === false) { // Avoid treating surrogate pairs as more than one character
            continue;
        }
        var code = _fixedCharCodeAt(c);
        output.push(code);
    }
    return output;
};
// Equality and Comparison of Strings
// Args are strings
XQueryFunctions.prototype.compare = function (comparand1, comparand2, collation) { // returns integer

};
XQueryFunctions.prototype['codepoint-equal'] = function (comparand1, comparand2) { // returns boolean
    return comparand1 === comparand2; // No normalization done in JS nor this function
};
// Functions on String Values
// Arguments are all strings, except in concat (xs:anyAtomicType) and substring (start and length are xs:double)
XQueryFunctions.prototype.concat = function () {
    var output = '';
    for (var i = 0, argl = arguments.length; i < argl; i++) {
        output += _toString(arguments[i]);
    }
    return output;
};
XQueryFunctions.prototype['string-join'] = function (arg1, arg2) {
    arg2 = typeof arg2 === 'undefined' ? '' : arg2;
    return arg1.join(arg2);
};
XQueryFunctions.prototype.substring = function (sourceString, start, length) { // Handles NaN and +/- Infinity 2nd, 3rd arguments
    function _substring (str, startIdx, endIdx) { // We can't use slice since it doesn't support surrogates
        var output = '';
        for (var c, started = false, i = 0, idx = 0, strl = str.length; i < strl; i++) { // We can't start with startIdx due to surrogate pair counting
            if ((c = _getWholeChar(str, i)) === false) { // Avoid treating surrogate pairs as more than one character
                continue;
            }
            if (idx === endIdx) {
                return output;
            }
            if (idx === startIdx) {
                started = true;
            }
            if (started) {
                output += c;
            }
            idx++;
        }
        return output;
    }
    if (isNaN(start) || typeof length !== 'undefined' && (isNaN(start + length))) {
        return '';
    }
    var startRounded = this.round(start)
    var onePlusStart = startRounded < 1 ? 0 : startRounded - 1; // Adjust for 1-based count
    if (typeof length === 'undefined') {
        return _substring(sourceString, onePlusStart);
    }
    var lengthRounded = this.round(length);
    var endIdx = startRounded + lengthRounded - 1;
    if (endIdx < onePlusStart) { // Also covers condition of endIdx < 0
        return '';
    }
    return _substring(sourceString, onePlusStart, endIdx);
};
XQueryFunctions.prototype['string-length'] = function (arg) {
    for (var i=0, lgth=0, argl = arg.length; i < argl; i++) {
        if (_getWholeChar(arg, i) === false) { // Avoid treating surrogate pairs as more than one character
            continue;
        }
        lgth++;
    }
    return lgth;
};
XQueryFunctions.prototype['normalize-space'] = function (arg) {
    return arg.replace(new RegExp('^' + WS + '+'), '').replace(new RegExp(WS + '+$'), '').
                    replace(new RegExp(WS + '+', 'g'), ' ');
};
XQueryFunctions.prototype['normalize-unicode'] = function (arg, normalizationForm) {
    var plugin = this.normalizeUnicodePlugin;
    if (!plugin) {
        throw 'This function requires the Unicode normalization plug-in';
    }

    var target = [];
    if (typeof normalizationForm === 'string') {
        normalizationForm = this['normalize-space'](normalizationForm).toUpperCase();
    }
    normalizationForm = typeof normalizationForm === 'undefined' ? 'NFC' : normalizationForm;

    var lookup;

    // Fix: do full normalization
    switch (normalizationForm) {
        case 'NFC': case 'NFD':
            lookup = plugin.canonByCodePt;
            break;
        case 'NFKC': case 'NFKD':
            lookup = plugin.compatByCodePt;
            break;
        case 'FULLY-NORMALIZED': // NFC, character references and entities resolved if would change by NFC (and no composing char or escape thereof at beginning))
            lookup = plugin.canonByCodePt;
            break;
        case '':
            return arg;
        default:
            throw new XQueryError('FOCH0003', 'Unsupported normalization form.');
    }

    // Decompose

    var _get_lookup = (normalizationForm === 'NFD') ? function (cs) { // Recursive
        var out = '';
        for (var i = 0, cslen = cs.length; i < cslen; i++) {
            if ((c = _getWholeChar(cs, i, true)) === false) { // Avoid treating surrogate pairs as more than one character
                continue;
            }
            var lc = lookup[c];
            if (!lc) {
                out += c;
            }
            else {
                out += _get_lookup(lookup[c]);
            }
        }
        return out;
    } : function (cs) { // Non-recursive
        var out = '';
        for (var i = 0, cslen = cs.length; i < cslen; i++) {
            if ((c = _getWholeChar(cs, i, true)) === false) { // Avoid treating surrogate pairs as more than one character
                continue;
            }
            var lc = lookup[c];
            if (!lc) {
                out += c;
            }
            else {
                out += lookup[c];
            }
        }
        return out;
    };

    var i, strl, c;
    for (i = 0, strl = arg.length; i < strl; i++) {
        if ((c = _getWholeChar(arg, i, true)) === false) { // Avoid treating surrogate pairs as more than one character
            continue;
        }

        var buffer = Hangul.decomposeHangulRecursively(_get_lookup(c)); // These are supposed to need to be done recursively, but my algorithm doesn't find any; for non-Hangul needing recursive decomp, see U+1E69

        // Reordering in decomposition
        var ch;
        for (var j = 0, buffl = buffer.length; j < buffl; j++) {
            if ((ch = _getWholeChar(buffer, j, true)) === false) { // Avoid treating surrogate pairs as more than one character
                continue;
            }

            var chClass = parseInt(plugin.cccs[ch] || 0, 10); // getCanonicalClass
            var k = target.length; // insertion point
            if (chClass != 0) {
                // bubble-sort combining marks as necessary
                var ch2;
                for (; k > 0; k--) {
                    if ((ch2 = _getWholeChar(target[k-1], 0, true)) === false) { // Avoid treating surrogate pairs as more than one character
                        continue;
                    }
                    if (parseInt(plugin.cccs[ch2] || 0, 10) <= chClass) {break;}
                }
            }
            target.splice(k, 0, ch);
        }
    }
    target = target.join('');

    if (normalizationForm === 'NFD' || normalizationForm === 'NFKD') {
        return target;
    }
    // Fix: do composition (including Hangul)


    return target;
};
XQueryFunctions.prototype['upper-case'] = function (arg) {
    return arg.toUpperCase();
};
XQueryFunctions.prototype['lower-case'] = function (arg) {
    return arg.toLowerCase();
};
XQueryFunctions.prototype['translate'] = function (arg, mapString, transString) {
    var output = '';
    if (typeof arg === 'object' && arg.length === 0) {
        return '';
    }
    if (mapString === '') {
        return arg;
    }
    for (var i = 0, as, argl = arg.length; i < argl; i++) {
        if ((as = _getWholeChar(arg, i)) === false) { // Avoid treating surrogate pairs as more than one character
            continue;
        }
        for (var ms, ts, ignore = false, mps = {}, m = 0, t = 0, msl = mapString.length; m < msl; m++, t++) {
            if ((ms = _getWholeChar(mapString, m)) === false) {
                t--;
                continue;
            }
            if ((ts = _getWholeChar(transString, t)) === false) {
                ts = _getWholeChar(transString, ++t);
            }
            if (as === ms && ts) { // If there is a match and a replacement, use the replacement
                ignore = true;
                output += mps[ms] ? mps[ms] : ts;
                break;
            }
            else if (as === ms) { // Do not add anything if there is a match but ts is not present on this iteration
                ignore = true;
                break;
            }
            if (!mps[ms]) { // Store first occurrence if may encounter again
                mps[ms] = ts;
            }
        }
        if (!ignore) {
            output += as;
        }
    }
    return output;
};
// Functions Based on Substring Matching
// All arguments are strings
XQueryFunctions.prototype.contains = function (arg1, arg2, collation) { // returns boolean

};
XQueryFunctions.prototype['starts-with'] = function (arg1, arg2, collation) { // returns boolean

};
XQueryFunctions.prototype['ends-with'] = function (arg1, arg2, collation) { // returns boolean

};
XQueryFunctions.prototype['substring-before'] = function (arg1, arg2, collation) { // returns string

};
XQueryFunctions.prototype['substring-after'] = function (arg1, arg2, collation) { // returns string

};
// String Functions that use Regular Expressions
// All arguments are strings
XQueryFunctions.prototype.matches = function (input, pattern, flags) {

};
XQueryFunctions.prototype.replace = function (input, pattern, replacement, flags) {

};
XQueryFunctions.prototype.tokenize = function (input, pattern, flags) {

};
XQueryFunctions.prototype['analyze-string'] = function (input, pattern, flags) {

};
// END STRING FUNCTIONS
// START URI FUNCTIONS
// All arguments are strings; all return strings except resolve-uri which returns "xs:anyURI?"
XQueryFunctions.prototype['resolve-uri'] = function (relative, base) {

};
XQueryFunctions.prototype['encode-for-uri'] = function (uri_part) {
    return encodeURIComponent(uri_part).replace(/!/g, '%21').replace(/'/g, '%27').replace(/\(/g, '%28').
                                                                replace(/\)/g, '%29').replace(/\*/g, '%2A');
};
XQueryFunctions.prototype['iri-to-uri'] = function (iri) {
    return encodeURI(iri).replace(/%5B/g, '[').replace(/%5D/g, ']');
};
XQueryFunctions.prototype['escape-html-uri'] = function (uri) {
    return uri.replace(/[^\u0020-\u007e]/g, function (s0) { // For some reason Mozilla at least is faster without '+' modifier
        return encodeURI(s0); // The characters this does not escape are not in the regex, so this will only escape all relevant
    });
};
// END URI FUNCTIONS
// START BOOLEAN FUNCTIONS
XQueryFunctions.prototype['true'] = function () {
    return true;
};
XQueryFunctions.prototype['false'] = function () {
    return false;
};

XQueryFunctions.prototype['boolean'] = function (arg) {
    return !!arg; // Fix: Do real type checking
};
XQueryFunctions.prototype.not = function (arg) {
    return !this['boolean'](arg);
};
// END BOOLEAN FUNCTIONS
// START DURATION FUNCTIONS
// Component Extraction Functions on Durations
// All take xs:duration as arguments and return integer (except for seconds-from-duration which returns decimal)
XQueryFunctions.prototype['years-from-duration'] = function (arg) {

};
XQueryFunctions.prototype['months-from-duration'] = function (arg) {

};
XQueryFunctions.prototype['days-from-duration'] = function (arg) {

};
XQueryFunctions.prototype['hours-from-duration'] = function (arg) {

};
XQueryFunctions.prototype['minutes-from-duration'] = function (arg) {

};
XQueryFunctions.prototype['seconds-from-duration'] = function (arg) {

};
// END DURATION FUNCTIONS
// START DATE AND TIME FUNCTIONS
// Constructing a dateTime
XQueryFunctions.prototype.dateTime = function (arg1, arg2) {

};
// Component Extraction Functions on Dates and Times
XQueryFunctions.prototype['year-from-dateTime'] = function (arg) {

};
XQueryFunctions.prototype['month-from-dateTime'] = function (arg) {

};
XQueryFunctions.prototype['day-from-dateTime'] = function (arg) {

};
XQueryFunctions.prototype['hours-from-dateTime'] = function (arg) {

};
XQueryFunctions.prototype['minutes-from-dateTime'] = function (arg) {

};
XQueryFunctions.prototype['seconds-from-dateTime'] = function (arg) {

};
XQueryFunctions.prototype['timezone-from-dateTime'] = function (arg) {

};
XQueryFunctions.prototype['year-from-date'] = function (arg) {

};
XQueryFunctions.prototype['month-from-date'] = function (arg) {

};
XQueryFunctions.prototype['day-from-date'] = function (arg) {

};
XQueryFunctions.prototype['timezone-from-date'] = function (arg) {

};
XQueryFunctions.prototype['hours-from-time'] = function (arg) {

};
XQueryFunctions.prototype['minutes-from-time'] = function (arg) {

};
XQueryFunctions.prototype['seconds-from-time'] = function (arg) {

};
XQueryFunctions.prototype['timezone-from-time'] = function (arg) {

};
// Timezone Adjustment Functions on Dates and Time Values
XQueryFunctions.prototype['adjust-dateTime-to-timezone'] = function (arg, timezone) {

};
XQueryFunctions.prototype['adjust-date-to-timezone'] = function (arg, timezone) {

};
XQueryFunctions.prototype['adjust-time-to-timezone'] = function (arg, timezone) {

};
// Formatting Dates and Times
// All return "xs:string?"
XQueryFunctions.prototype['format-dateTime'] = function (value, picture, language, calendar, country) {

};
XQueryFunctions.prototype['format-date'] = function (value, picture, language, calendar, country) {

};
XQueryFunctions.prototype['format-time'] = function (value, picture, language, calendar, country) {

};
// END DATE AND TIME FUNCTIONS
// START QNAME FUNCTIONS
// Functions to create a QNames
// Both return xs:QName
XQueryFunctions.prototype['resolve-QName'] = function (qname, element) {
    var pos = qname.indexOf(':');
    var namespaceURI;
    if (pos !== -1) {
        var prefix = qname.slice(0, pos);
        namespaceURI = this['namespace-uri-for-prefix'](prefix, element);
        if (namespaceURI === null) {
            throw new XPathXQueryFunctionsOperatorsError('FONS0004', 'No namespace found for prefix.');
        }
    }
    else {
        namespaceURI = this['namespace-uri-for-prefix']('', element);
    }
    return new QName(namespaceURI, qname); // Will check for qname formedness errors
};
XQueryFunctions.prototype.QName = function (paramURI, paramQName) {
    return new QName(paramURI, paramQName);
};
// Functions and Operators Related to QNames
XQueryFunctions.prototype['prefix-from-QName'] = function (arg) { // returns "xs:NCName?"
    return arg.prefix; // Non-existent to return empty sequence
};
XQueryFunctions.prototype['local-name-from-QName'] = function (arg) { // returns "xs:NCName?"
    return arg.localName;
};
XQueryFunctions.prototype['namespace-uri-from-QName'] = function (arg) { // returns "xs:anyURI?"
    return arg.URI;
};
XQueryFunctions.prototype['namespace-uri-for-prefix'] = function (prefix, element) { // returns "xs:anyURI?"
    return lookupNamespaceURI(element, prefix);
    function lookupNamespaceURI (node, prefix) { // adapted from http://www.w3.org/TR/DOM-Level-3-Core/namespaces-algorithms.html#lookupNamespaceURIAlgo
        var htmlMode = document.contentType;
        var xmlnsPattern = /^xmlns:(.*)$/;
        if (node.lookupNamespaceURI && htmlMode !== 'text/html') {
            return node.lookupNamespaceURI(prefix);
        }
        switch (node.nodeType) {
            case 1: // ELEMENT_NODE (could also just test for Node.ELEMENT_NODE, etc., if supported in all browsers)
                if (node.namespaceURI !== null && node.prefix === prefix)  {
                // Note: prefix could be "null" in this case we are looking for default namespace
                    return node.namespaceURI;
                }
                if (node.attributes.length) {
                    for (var i=0; i < node.attributes.length; i++) {
                        var att = node.attributes[i];
                        xmlnsPattern.lastIndex = 0;
                        if (att.name.search(xmlnsPattern) !== -1 && xmlnsPattern.exec(att.name)[1] === prefix) {
                            if (att.value) {
                                return att.value;
                            }
                            return null; // unknown
                        }
                        else if (att.name === 'xmlns' && prefix === null) {
                        // default namespace
                            if (att.value) {
                                return att.value;
                            }
                            return null; // unknown
                        }
                    }
                }
                if (node.parentNode && node.parentNode.nodeType !== 9) {
                // EntityReferences may have to be skipped to get to it
                    return lookupNamespaceURI(node.parentNode, prefix);
                }
                return null;
            default:
                throw 'Node type not allowed for element argument of namespace-uri-for-prefix';
        }
    }
};
XQueryFunctions.prototype['in-scope-prefixes'] = function (element) { // returns "xs:string*"
    return getUniqueElementPrefixes(element);
    function getUniqueElementPrefixes (element) {
        function push (arr, item) {
            for (var i = 0, arrl = arr.length; i < arrl; i++) {
                if (arr[i] === item) {
                    return;
                }
            }
            arr.push(item);
        }
        var arr = [];
        var xmlnsPattern = /^xmlns:(.*)$/;
        switch (element.nodeType) {
            case 1: // ELEMENT_NODE (could also just test for Node.ELEMENT_NODE, etc., if supported in all browsers)
                var i;
                if (element.attributes.length) {
                    for (i=0; i < element.attributes.length; i++) {
                        var att = element.attributes[i];
                        xmlnsPattern.lastIndex = 0;
                        if (att.name.search(xmlnsPattern) !== -1) {
                            push(arr, att.name.slice(6)); // skip over xmlns:  (Fix: Define as xs:NCName?)
                        }
                        else if (att.name === 'xmlns') {
                            // default namespace
                            push(arr, ''); // Fix: Define with type xs:string?
                        }
                    }
                }
                if (element.parentNode && element.parentNode.nodeType !== 9) {
                // EntityReferences may have to be skipped to get to it
                    var arr2 = getUniqueElementPrefixes(element.parentNode);
                    for (i = 0; i < arr2.length; i++) {
                        push(arr, arr2[i]);
                    }
                }
                return arr;
            default:
                throw 'Node type not allowed for element argument of in-scope-prefixes';
        }
    }
};
// END QNAME FUNCTIONS
// START NODE FUNCTIONS
XQueryFunctions.prototype.name = function (arg) { // returns string

};
XQueryFunctions.prototype['local-name'] = function (arg) { // returns string

};
XQueryFunctions.prototype['namespace-uri'] = function (arg) { // returns xs:anyURI

};
XQueryFunctions.prototype.number = function (arg) { // returns double

};
XQueryFunctions.prototype.lang = function (testlang, node) { // returns xs:boolean

};
XQueryFunctions.prototype.root = function (arg) { // returns "node()" or "node()?"

};
// END NODE FUNCTIONS
// START SEQUENCE FUNCTIONS

// END SEQUENCE FUNCTIONS
// START CONTEXT FUNCTIONS
// None have any arguments
XQueryFunctions.prototype.position = function () { // returns integer

};
XQueryFunctions.prototype.last = function () { // returns integer

};
XQueryFunctions.prototype['current-dateTime'] = function () { // returns "xs:dateTimeStamp"

};
XQueryFunctions.prototype['current-date'] = function () { // returns "xs:date"

};
XQueryFunctions.prototype['current-time'] = function () { // returns "xs:time"

};
XQueryFunctions.prototype['implicit-timezone'] = function () { // returns "xs:dayTimeDuration"

};
XQueryFunctions.prototype['default-collation'] = function () { // returns "xs:string"

};
XQueryFunctions.prototype['static-base-uri'] = function () { // returns "xs:anyURI?"

};
// END CONTEXT FUNCTIONS
// START FUNCTION FUNCTIONS
XQueryFunctions.prototype['function-name'] = function (func) { // returns "xs:QName?"

};
XQueryFunctions.prototype['function-arity'] = function (func) { // returns integer

};
XQueryFunctions.prototype['partial-apply'] = function (func, arg, argNum) { // returns function

};
// END FUNCTION FUNCTIONS

// START General Functions and Operators on Sequences
XQueryFunctions.prototype['index-of'] = function () { // returns integer*

};
XQueryFunctions.prototype.empty = function () { // returns boolean

};
XQueryFunctions.prototype.exists = function () { // returns boolean

};
XQueryFunctions.prototype['distinct-values'] = function () { // returns xs:anyAtomicType*

};
XQueryFunctions.prototype['insert-before'] = function () { // returns item*

};
XQueryFunctions.prototype.remove = function () { // returns item*

};
XQueryFunctions.prototype.reverse = function () { // returns item*

};
XQueryFunctions.prototype.subsequence = function () { // returns item*

};
XQueryFunctions.prototype.unordered = function () { // returns item*

};
// END General Functions and Operators on Sequences

// START Functions That Test the Cardinality of Sequences
XQueryFunctions.prototype['zero-or-one'] = function () { // returns item?

};
XQueryFunctions.prototype['one-or-more'] = function () { // returns item+

};
XQueryFunctions.prototype['exactly-one'] = function () { // returns item

};
// END Functions That Test the Cardinality of Sequences

// START Equals, Union, Intersection and Except
XQueryFunctions.prototype['deep-equal'] = function () { // returns boolean

};
// END Equals, Union, Intersection and Except

// START Aggregate Functions
XQueryFunctions.prototype.count = function () { // returns integer

};
XQueryFunctions.prototype.avg = function () { // returns xs:anyAtomicType?

};
XQueryFunctions.prototype.max = function () { // returns xs:anyAtomicType?

};
XQueryFunctions.prototype.min = function () { // returns xs:anyAtomicType?

};
XQueryFunctions.prototype.sum = function () { // returns xs:anyAtomicType?

};
// END Aggregate Functions

// START Functions and Operators that Generate Sequences
XQueryFunctions.prototype.id = function () { // returns element()*

};
XQueryFunctions.prototype.idref = function () { // returns node()*

};
XQueryFunctions.prototype.doc = function () { // returns document-node()?

};
XQueryFunctions.prototype['doc-available'] = function () { // returns boolean

};
XQueryFunctions.prototype.collection = function () { // returns node()*

};
XQueryFunctions.prototype['element-with-id'] = function () { // returns element()*

};
// END Functions and Operators that Generate Sequences



// STATIC PRIVATE METHODS
/**
 * @private
 * @constant
 */
function _escRegExp (str) {
    return str.replace(/[.\\+*?\[\^\]$(){}=!<>|:\-]/g, '\\$&');
}


// PRIVATE NON-PARSING INSTANCE METHODS

/**
 * Increases the index 'n' chars
 * @private
 * @param {Number} numberOfChars The number of characters to advance the index
 * @throws EndOfInputException
*/
function _nextNChar (numberOfChars) {
    this._i += numberOfChars;
    if (this._i >= this._x.length) {
        throw new EndOfInputException();
    }
}


/**
 * @private
 * @param {RegExp} regExp Expects non-global RegExp
 */
function _findRegExp (regExp) {
    // var oldIndex = this._i;
    var inc = this._x.slice(this._i).match(regExp);
    if (inc && inc[0]) {
        _nextNChar.call(this, inc[0].length);
        return inc; // this._x.slice(oldIndex, this._i);
    }
    return false;
}


// CONSTRUCTOR
/**
 * 
 * @constructor
 * @param {String} xquery
 * @param {String} [xml] The XML against which output will be run; if omitted, will just execute handlers (?)
 * @param {Object} options Object with optional properties:
 *                                                  'version' ('1'|'1.1'), 'update' (true|false), 'fulltext' (true|false), 'scripting' (true|false)
 * @param {Object} handlerObj Handler object with methods: 'versionDecl', ...
 */
function XQueryParser (xquery, xml, options, handlerObj) {
    this._x = xquery;
    this._xml = xml;
    this._i = 0;
    this._h = handlerObj || {};
    this._moduleNSs = {};
    // this._reportedVersion; // Set in script
    // this._versionInUse; // Set in script
    // this._defaultElementNamespace; // Set in script
    // this._defaultFunctionNamespace; // Set in script
    this.language = (options && options.language) || 'en'; // format-integer, format-date, format-dateTime, format-time

    // this._boundarySpace; // Set in script
    this._decFormatObj = {}; // Populated in script
    this._namespaceDecls = {}; // Populated in script

    this.setVersion((options && options.version) || '1.1'); // defaults to 1.1

    // Options with default true
    this._update = !options || options.update;
    this._fullText = !options || options.fullText;
    this._scripting = !options || options.scripting;
}

// PUBLIC METHODS

/**
 * Begins the parsing
 */
XQueryParser.prototype.parse = function () {
    this._Query();
};

/**
 *
 */
XQueryParser.prototype.getVersion = function () {
    return this._version;
};

/**
 *
 */
XQueryParser.prototype.getUpdate = function () {
    return this._update;
};

/**
 *
 */
XQueryParser.prototype.getFullText = function () {
    return this._fullText;
};

/**
 *
 */
XQueryParser.prototype.getScripting = function () {
    return this._scripting;
};

/**
 *
 * @throws 'Unrecognized version'
 */
XQueryParser.prototype.setVersion = function (str) {
    switch (str) {
        case '1.0': case '1.1': // Fall-through
            break;
        case 'query-defined':
            this._queryDefined = true;
            return;
        default:
            throw 'Unrecognized version';
    }
    this._version = str;
};

/**
 *
 */
XQueryParser.prototype.setUpdate = function (bool) {
    this._update = bool;
};

/**
 *
 */
XQueryParser.prototype.setFullText = function (bool) {
    this._fullText = bool;
};

/**
 *
 */
XQueryParser.prototype.setScripting = function (bool) {
    this._scripting = bool;
};


// PRIVATE PARSING METHODS (with same names as EBNF classes, prefixed with '_')


/**
 * This is not an EBNF-defined class, but defined as a concept
 *    in XQuery (hopefully accurately represented here)
 * "[Definition: A query consists of one or more modules.] If a query
 *  is executable, one of its modules has a Query Body containing an
 *  expression whose value is the result of the query."
 *  @throws _EOFError
 * @returns {Boolean}
 */
XQueryParser.prototype._Query = function () {
    this._Module(); // Make sure there is a chance to get an EOF error
    try {
        while (this._Module()) { // Keep parsing until reaching the end of hte file
        }
    }
    catch(e) {
        if (e.message !== _EOFError) { // Eat EOF since already checked above
            throw e;
        }
    }
    return true;
};
/**
 *
 * @throws _EOFError
 * @returns {Boolean}
 */
XQueryParser.prototype._Module = function () {
    this._VersionDecl(); // Optional
    this._LibraryModule() || this._MainModule() || (function () {throw _EOFError;}());
    return true;
};

/**
 *
 * @throws XQueryError
 * @returns {Boolean}
 */
XQueryParser.prototype._VersionDecl = function () {
    // Fix: To be allowed onlly once across modules or?
    var version = this._version || '1.0', encoding = 'utf-8', explicit = false, decl11;

    var decl10 = _findRegExp.call(this, new RegExp('^\\s*xquery\\s+version\\s+(' + _StringLiteral +
                                                                                ')(\\s+encoding\\s+(' + _StringLiteral + '))?' +
                                                                                '\\s*' + _strSeparator + '\\s*'));
    var vers10 = (decl10 && decl10[1]);
    if (!vers10) {
        decl11 = _findRegExp.call(this, new RegExp('^\\s*xquery\\s+encoding\\s+' + _StringLiteral + '\\s*'+_strSeparator));
    }
    if (decl10 || decl11) {
        explicit = true;
    }
    version = vers10 || version;
    if (version !== '1.0' && version !== '1.1') {
        throw new XQueryError('XQST0031', 'The version number specified in the version declaration is not supported by the implementation.');
    }
    encoding = (vers10 && vers10[2]) || (decl11 && decl11[1]) || encoding;
    if (!encoding.match(/^[A-Za-z]([A-Za-z0-9._]|-)*$/)) {
        throw new XQueryError('XQST0087', 'The encoding specified in the Version Declaration does not conform to the definition of EncName specified in [XML 1.0].');
    }
    this._reportedVersion = version;
    
    this._versionInUse = this._queryDefined ? this._reportedVersion : this._version;

    if (explicit && this._h.versionDecl) {
        this._h.versionDecl(version, encoding, explicit);
    }
    return true; // Optional
};


/**
 * @returns {Boolean}
 */
XQueryParser.prototype._LibraryModule = function () {
    var decl = this._ModuleDecl();
    if (!decl) {
        return false;
    }
    this._Prolog(); // optional
    // We don't report anything here as constituents have own handlers
    return true;
};

/**
 * @returns {Boolean}
 */
XQueryParser.prototype._MainModule = function () {
    this._Prolog(); // optional
    var body = this._QueryBody();
    // We don't report anything here as constituents have own handlers
    return body !== false;
};


/**
 *
 * @returns {Boolean}
 */
XQueryParser.prototype._Prolog = function () {
    // First part, whether XQuery 1.0 or 1.1
    // We can call _Separator because all of these methods should not find false positives
    while ((this._DefaultNamespaceDecl() || this._Setter() || this._NamespaceDecl() || this._Import())) { // All optional
        this._Separator();
    }
    if (this._versionInUse === '1.1') {
        while ((this._VarDecl() || this._ContextItemDecl() || this._FunctionDecl() | this._OptionDecl())) {
            this._Separator();
        }
    }
    else {
        while ((this._VarDecl() || this._FunctionDecl() | this._OptionDecl())) {
            this._Separator();
        }
    }
    // We don't report anything here as constituents have own handlers
    return true;
};

/**
 *
 * @returns {Boolean}
 */
XQueryParser.prototype._ModuleDecl = function () {
    var decl = _findRegExp.call(this, new RegExp(
        '^\\s*module\\s+namespace\\s+('+_NCName+')\\s*=\\s*('+_URILiteral+')\\s*' + _strSeparator
    ));
    if (!decl) {
        return false;
    }
    var name = decl[0], uri = decl[1];

    if (!uri) {
        throw new XQueryError('XQST0088', 'The literal that specifies the target namespace in a module import or a module declaration is of zero length.');
    }
    if (name.match(/^xml|xmlns$/i)) { // Fix: Presumably case-insensitive, but not specified
        throw new XQueryError('XQST0070', 'It is an error if a namespace URI is bound to the predefined prefix xmlns, or if a namespace URI other than http://www.w3.org/XML/1998/namespace is bound to the prefix xml, or if the prefix xml is bound to a namespace URI other than http://www.w3.org/XML/1998/namespace.');
    }

    if (this._usedPrefixes[name]) {
        throw new XQueryError('XQST0033', 'It is an error if a module contains multiple bindings for the same namespace prefix');
    }
    this._usedPrefixes[name] = name; // Track

    this._moduleNSs[name] = uri;
    if (this._h.moduleDecl) {
        this._h.moduleDecl(name, uri); // NCName, URILiteral
    }
    return true;
};

/**
 * Checks whether there is a separator; if not, throw an error
 * @throws UnexpectedToken
 * @returns {Boolean}
 */
XQueryParser.prototype._Separator = function () {
    if (!_findRegExp.call(this, /^\s*;/)) {
        throw new UnexpectedToken(';');
    }
    // We don't report this as a handler, since it is just an expected string
    return true;
};


/**
 * @returns {Boolean}
 */
XQueryParser.prototype._DefaultNamespaceDecl = function () {
    var nsType, ns;
    var decl = _findRegExp.call(this, new RegExp('^\\s*declare\\s+default\\s+(element|function)\\s+namespace\\s+('+_URILiteral + ')'));
    if (!decl) {
        return false;
    }
    nsType = decl[0];
    ns = decl[1]; // Fix: whitespace normalize per xs:anyURI?

    if (nsType === 'element') {
        if (this._defaultElementNamespace) {
            throw new XQueryError('XQST0066', 'A Prolog may not contain more than ' +
                                                                                        'one default element/type namespace declaration.');
        }
        this._defaultElementNamespace = ns;
    }
    else {
        if (this._defaultFunctionNamespace) {
            throw new XQueryError('XQST0066', 'A Prolog may not contain more than ' +
                                                                                        'one default function namespace declaration.');
        }
        this._defaultFunctionNamespace = ns;
    }

    if (decl && this._h.defaultNamespaceDecl) {
        this._h.defaultNamespaceDecl(nsType, ns); // ('element'|'function'), URILiteral
    }
    return true;
};


/**
 *
 * @returns {Boolean}
 */
XQueryParser.prototype._Setter = function () {
    // We don't report anything here as constituents have own handlers
    return this._BoundarySpaceDecl() || this._DefaultCollationDecl() || this._BaseURIDecl() ||
        this._ConstructionDecl() || this._OrderingModeDecl() || this._EmptyOrderDecl() ||
        this._CopyNamespacesDecl() ||
        (this._versionInUse === '1.1' && this._DecimalFormatDecl()) || false;
};


/**
 *
 * @returns {Boolean}
 */
XQueryParser.prototype._NamespaceDecl = function () {
    var ncName, ns;
    var decl = _findRegExp.call(this, new RegExp('^\\s*declare\\s+namespace\\s+('+_NCName+')\\s*=\\s*('+_URILiteral + ')'));

    if (!decl) {
        return false;
    }
    ncName = decl[0];
    ns = decl[1]; // Fix: whitespace normalize per xs:anyURI?

    if (ncName === 'xml' || ncName === 'xmlns') {
        throw new XQueryError('XQST0070', 'The predefined prefixes xml or xmlns must not appear in a namespace declaration');
    }
    if (ns === _XMLNamespace) {
        throw new XQueryError('XQST0070', 'A prefix other than xml may not be bound to the namespace URI http://www.w3.org/XML/1998/namespace.');
    }
    if (ns === _xmlnsNamespace) {
        throw new XQueryError('XQST0070', 'A prefix other than xmlns may not be bound to the namespace URI http://www.w3.org/2000/xmlns/.');
    }

    if (this._usedPrefixes[ncName]) {
        throw new XQueryError('XQST0033', 'It is an error if a module contains multiple bindings for the same namespace prefix');
    }
    this._usedPrefixes[ncName] = ncName; // Track

    this._namespaceDecls[ncName] = ns; // Already detected above that prefix not in use

    if (this._h.namespaceDecl) {
        this._h.namespaceDecl(ncName, ns); // NCName, URILiteral
    }
    return true;
};


/**
 *
 * @returns {Boolean}
 */
XQueryParser.prototype._Import = function () {
    // We don't report anything here as constituents have own handlers
    return this._SchemaImport() || this._ModuleImport();
};


// UNFINISHED

/**
 *
 * @returns {Boolean}
 */
XQueryParser.prototype._VarDecl = function () {
    // if part of a library module, ensure module declaration's namespace used or throw:
    // Build optional "static analysis" check
    // @throws XQueryError
    // throw new XQueryError('XQST0048', 'A function or variable declared in a library module is not in the target namespace of the library module.');
	// TypeDeclaration = "as" SequenceType
    // "declare" "variable" "$" _QName TypeDeclaration? ((":=" ExprSingle) | "external")

    // "declare" "variable" "$" _VarName TypeDeclaration? ((":=" VarValue) | ("external" (":=" VarDefaultValue)?))

    //ndebeiss : waiting for implementation, look for a separator
    if (_findRegExp.call(this, /^\s*;/)) {
        return true;
    }
    return false;
};

/**
 * 
 * @x-xmlversion 1.1
 * @returns {Boolean}
 */
XQueryParser.prototype._ContextItemDecl = function () {
    if (_findRegExp.call(this, /^\s*;/)) {
        return true;
    }
    return false;
};


/**
 *
 * @returns {Boolean}
 */
XQueryParser.prototype._FunctionDecl = function () {
    // if part of a library module, ensure module declaration's namespace used or throw:
    // @throws XQueryError
    // throw new XQueryError('XQST0048', 'A function or variable declared in a library module is not in the target namespace of the library module.');
    // "Static analysis" check:
    var funcOpts;
    var decl = _findRegExp.call(this, new RegExp('^\\s*declare\\s+(' + _FunctionOptions +
                                                                                            ')\\s+function\\s+' + _QName + '\\s*\\(\\s*(' + _ParamList +
                                                                                            '?)\\s*\\)\\s*(as\\s+' + _SequenceType + ')?\\s*(' +
                                                                                            _FunctionBody + '|external)'));
    if (!decl) {
        return false;
    }

    funcOpts = decl[0];
    if (this._h.FunctionDecl) {
        this._h.FunctionDecl(funcOpts); // "private" | "public" / "deterministic" | "nondeterministic"
    }
    return true;
};

/**
 *
 * @returns {Boolean}
 */
XQueryParser.prototype._OptionDecl = function () {
    var qName, option;
    var decl = _findRegExp.call(this, new RegExp('^\\s*declare\\s+option\\s+('+_QName+')\\s+('+_StringLiteral + ')'));
    if (!decl) {
        return false;
    }

    qName = decl[0];
    option = decl[1];

    if (this._h.optionDecl) {
        this._h.optionDecl(qName, option); // QName, StringLiteral
    }
    return true;
};



/**
 *
 * @returns {Boolean}
 */
XQueryParser.prototype._QueryBody = function () {
    // throw an exception if already run, as should only be one?
    // QueryBody = _Expr
    var decl = _findRegExp.call(this, new RegExp(_Expr));
    if (!decl) {
        return false;
    }
    return true;
};

/**
 *
 * @returns {Boolean}
 */
XQueryParser.prototype._BoundarySpaceDecl = function () {
    var bs;
    var decl = _findRegExp.call(this, new RegExp('^\\s*declare\\s+boundary-space\\s+(preserve|strip)'));
    if (!decl) {
        return false;
    }
    bs = decl[0];
    this._boundarySpace = bs; // Fix: error checking for previous settings, etc.?
    if (this._h.boundarySpaceDecl) {
        this._h.boundarySpaceDecl(bs); // boundary-space ('preserve'|'strip')
    }
    return true;
};

/**
 *
 * @returns {Boolean}
 */
XQueryParser.prototype._DefaultCollationDecl = function () {
    var collationURI;
    var decl = _findRegExp.call(this, new RegExp('^\\s*declare\\s+default\\s+collation\\s+('+_URILiteral + ')'));
    if (!decl) {
        return false;
    }
    collationURI = decl[0];
    if (this._h.defaultCollationDecl) {
        this._h.defaultCollationDecl(collationURI); // URILiteral
    }
    return true;
};

/**
 *
 * @returns {Boolean}
 */
XQueryParser.prototype._BaseURIDecl = function () {
    var baseURI;
    var decl = _findRegExp.call(this, new RegExp('^\\s*declare\\s+base-uri\\s+('+_URILiteral + ')'));
    if (!decl) {
        return false;
    }
    baseURI = decl[0];
    if (this._h.defaultCollationDecl) {
        this._h.defaultCollationDecl(baseURI); // URILiteral
    }
    return true;
};

/**
 *
 * @returns {Boolean}
 */
XQueryParser.prototype._ConstructionDecl = function () {
    var constr;
    var decl = _findRegExp.call(this, new RegExp('^\\s*declare\\s+construction\\s+(strip|preserve)'));
    if (!decl) {
        return false;
    }
    constr = decl[0];

    if (this._h.constructionDecl) {
        this._h.constructionDecl(constr); // construction ('strip'|'preserve')
    }
    return true;
};

/**
 *
 * @returns {Boolean}
 */
XQueryParser.prototype._OrderingModeDecl = function () {
    var ordering;
    var decl = _findRegExp.call(this, new RegExp('^\\s*declare\\s+ordering\\s+(ordered|unordered)'));
    if (!decl) {
        return false;
    }
    ordering = decl[0];
    if (this._h.orderingModeDecl) {
        this._h.orderingModeDecl(ordering); // ordering ('ordered'|'unordered')
    }
    return true;
};

/**
 *
 * @returns {Boolean}
 */
XQueryParser.prototype._EmptyOrderDecl = function () {
    var emptyOrder;
    var decl = _findRegExp.call(this, new RegExp('^\\s*declare\\s+default\\s+order\\s+empty\\s+(greatest|least)'));
    if (!decl) {
        return false;
    }
    emptyOrder = decl[0];
    if (this._h.emptyOrderDecl) {
        this._h.emptyOrderDecl(emptyOrder); // ('greatest'|'least')
    }
    return true;
};

/**
 *
 * @returns {Boolean}
 */
XQueryParser.prototype._CopyNamespacesDecl = function () {
    var preservation, inheritance;
    var decl = _findRegExp.call(this,
        new RegExp('^\\s*declare\\s+copy-namespaces\\s+('+_PreserveMode+')\\s*,\\s*('+_InheritMode+')'));
    if (!decl) {
        return false;
    }
    preservation = decl[0];
    inheritance = decl[1];
    if (this._h.copyNamespacesDecl) {
        this._h.copyNamespacesDecl(preservation, inheritance); // ('preserve'|'no-preserve'), ('inherit'|'no-inherit')
    }
    return true;
};

/**
 * @x-xmlversion 1.1
 * @returns {Boolean}
 */
XQueryParser.prototype._DecimalFormatDecl = function () {
    var formatName, decFormatPropPairs, decFormatPropPattern = '((?:('+_DFPropertyName + ')\\s*=\\s*('+_StringLiteral + ')\\s*)*)';
    var decl = _findRegExp.call(this,
        new RegExp('^\\s*declare\\s+(?:decimal-format\\s+('+_QName+')|default\\s+decimal-format)\\s+'+
                                    decFormatPropPattern));
    if (!decl) {
        return false;
    }
    formatName = decl[0];
    if ((formatName && this._decFormatObj[formatName]) ||
        (!formatName && this._dfDefault)
    ) { // No two with same name and no two defaults
        throw new XQueryError('XQST...unknown... though says XQST0096',
            '(Need to fill in with exact error in specification after fixed)'); // Fix: XQST0096 is not correct: See http://www.w3.org/Bugs/Public/show_bug.cgi?id=10271
    }
    formatName = formatName || '-default'; // We indicate a default value by '-default' as that is not an allowable QName
    this._decFormatObj[formatName] = {};
    decFormatPropPairs = decl[1];
    if (decFormatPropPairs) { // Might not be any, though appears to me there should be: http://www.w3.org/Bugs/Public/show_bug.cgi?id=10273
        var decFormatPropRegExp = new RegExp(decFormatPropPattern);
        var pairs, usedValues = {};
        while ((pairs = decFormatPropRegExp.exec(decFormatPropPairs)) != null) {
            if (this._decFormatObj[formatName][pairs[0]]) { // Already declared property for this decimal format name
                // throw new XQueryError('XQST...unknown...', ''); // Should probably be a bug: http://www.w3.org/Bugs/Public/show_bug.cgi?id=10272
            }
            if (usedValues[pairs[1]]) {
                throw new XQueryError('XQST0098', 'For any named or unnamed decimal format, the ' +
                    'properties representing characters used in a picture string should each have distinct values');
            }
            if (pairs[1].length > 1 || /^[\ud800-\udb7f][\udc00-\udfff]$/) { // Fix: Multi-byte check needed? // Fix: to allow private surrogates, the last character in the first range should instead be \udbff
                throw new XQueryError('XQST0100', 'It is a static error if the decimal format property ' + pairs[0] + ' is not a single character');
            }
            switch (pairs[0]) { // "statically known decimal formats"
                case 'decimal-separator': case 'grouping-separator': case 'percent-sign':
                case 'per-mille-sign':
                case 'digit-sign': case 'pattern-separator-sign':
                    break;
                case 'zero-digit':
                    // Unicode category Nd and must have 0 value
                    var zeroDigitPattern = /^[\u0030\u0660\u06F0\u07C0\u0966\u09E6\u0A66\u0AE6\u0B66\u0BE6\u0C66\u0CE6\u0D66\u0E50\u0ED0\u0F20\u1040\u1090\u17E0\u1810\u1946\u19D0\u1B50\u1BB0\u1C40\u1C50\uA620\uA8D0\uA900\uAA50\uFF10\u104A0\u1D7CE\u1D7D8\u1D7E2\u1D7EC\u1D7F6]$/; // as of 5.2
                    if (!pairs[1].match(zeroDigitPattern)) {
                        throw new XQueryError('XQST0097', 'A decimal-format should not specify a value that is not legal for a given "statically known decimal formats" property');
                    }
                    break;
                default:
                    throw 'Unrecognized static decimal format ';
            }
            this._decFormatObj[formatName][pairs[0]] =pairs[1];
            usedValues[pairs[1]] = true;
        }
    }
    if (this._h.decimalFormatDecl) {
        this._h.decimalFormatDecl(formatName, this._decFormatObj[formatName]); // (QName|'-default'), (Object of DFPropertyName-value pairs)
    }
    return true;
};

/**
 *
 * @returns {Boolean}
 */
XQueryParser.prototype._SchemaImport = function () {
    // Fix: track nss, etc.; move _SchemaPrefix above when done
    var targetNS, targetNSIsDefault, schemaNSURI, schemaLocation,
        _SchemaPrefix = '(?:namespace\\s+('+_NCName+')\\s*=\\s*|(default)\\s+element\\s+namespace\\s+)';
    var schemaImport = _findRegExp.call(this, new RegExp('^\\s*import\\s+schema\\s+'+_SchemaPrefix+
                                                                                                '?('+_URILiteral+')\\s+at\\s+('+_URILiteral+')((?:\\s*,\\s*('+_URILiteral+'))*)'));
    if (!schemaImport) {
        return false;
    }
    targetNS = schemaImport[0];
    targetNSIsDefault = schemaImport[1] === 'default';
    schemaNSURI = schemaImport[2];
    schemaLocation = schemaImport[3];
    // Fix: get additional URLs by exec
    if (this._h.schemaImport) {
        this._h.schemaImport(targetNS, targetNSIsDefault, schemaNSURI, schemaLocation);
    }


var name;
    if (this._usedPrefixes[name]) {
        throw new XQueryError('XQST0033', 'It is an error if a module contains multiple bindings for the same namespace prefix');
    }
    this._usedPrefixes[name] = name; // Track

    return true;
};

/**
 *
 * @returns {Boolean}
 */
XQueryParser.prototype._ModuleImport = function () {
// Fix: implement, following copying SchemaImport as similar base
    var moduleImport = _findRegExp.call(this, new RegExp('^\\s*import\\s+module\\s+(namespace\\s+('+_NCName+')\\s*=\\s*)?('+_URILiteral+')\\s+at\\s+('+_URILiteral+')((?:\\s*,\\s*('+_URILiteral+'))*)'));
    if (!moduleImport) {
        return false;
    }
    targetNS = moduleImport[0];
    moduleNSURI = moduleImport[1];
    moduleLocation = moduleImport[2];
    // Fix: get additional URLs by exec
    if (this._h.moduleImport) {
        this._h.moduleImport(targetNS, moduleNSURI, moduleLocation);
    }
var name;
    if (this._usedPrefixes[name]) {
        throw new XQueryError('XQST0033', 'It is an error if a module contains multiple bindings for the same namespace prefix');
    }
    this._usedPrefixes[name] = name; // Track

    return true;
};

/**
 *
 * @returns {Boolean}
 */
XQueryParser.prototype._ = function () {

    return true;
};

/**
 *
 * @returns {Boolean}
 */
XQueryParser.prototype._ = function () {

    return true;
};

/**
 *
 * @returns {Boolean}
 */
XQueryParser.prototype._ = function () {

    return true;
};

/**
 *
 * @returns {Boolean}
 */
XQueryParser.prototype._ = function () {

    return true;
};

/**
 *
 * @returns {Boolean}
 */
XQueryParser.prototype._ = function () {

    return true;
};

/**
 *
 * @returns {Boolean}
 */
XQueryParser.prototype._ = function () {

    return true;
};

/**
 *
 * @returns {Boolean}
 */
XQueryParser.prototype._ = function () {

    return true;
};

/**
 *
 * @returns {Boolean}
 */
XQueryParser.prototype._ = function () {

    return true;
};

/**
 *
 * @returns {Boolean}
 */
XQueryParser.prototype._ = function () {

    return true;
};

/**
 *
 * @returns {Boolean}
 */
XQueryParser.prototype._ = function () {

    return true;
};

/**
 *
 * @returns {Boolean}
 */
XQueryParser.prototype._ = function () {

    return true;
};

/**
 *
 * @returns {Boolean}
 */
XQueryParser.prototype._ = function () {

    return true;
};

/**
 *
 * @returns {Boolean}
 */
XQueryParser.prototype._ = function () {

    return true;
};

/**
 *
 * @returns {Boolean}
 */
XQueryParser.prototype._ = function () {

    return true;
};

/**
 *
 * @returns {Boolean}
 */
XQueryParser.prototype._ = function () {

    return true;
};

// EXPORTS
this.XQueryDynamicError = XQueryDynamicError;
this.XQueryParser = XQueryParser;
this.XQueryFunctions = XQueryFunctions;
this.XQueryAccessors = XQueryAccessors;
this.XQueryOperators = XQueryOperators;
this.XQueryError = XQueryError;

}());
